Discussion:
General purpose utilities for template metaprogramming and type manipulation
(too old to reply)
Vincent Reverdy
2018-03-04 06:55:38 UTC
Permalink
Hey,

I was starting to think about putting together a proposal to add minor
helper classes to either type_traits/utility/tuple to help with some of the
operations done again and again when doing template metaprogramming.
Here is a list of a few I can think of, but I would have liked to hear
other suggestions. Names are just indicative, and bikeshedding would happen
for all of these types.


- *std::blank*, defined as an empty struct
struct blank{};
- *std::pack*, to hold a parameter pack of type
template <class... T> struct pack{};
- *std::convertible*, a type convertible to anything
struct convertible{template <class T> constexpr operator T() const
noexcept;};
- *std::copy_qualifiers*, a type traits copying ref and cv qualifiers
from one type to another
template <class From, class To> struct copy_qualifiers {using type = /*
cv-ref qualfiers of From applied to To*/;};

Other suggestions?
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/e3415a75-7e20-48dd-9e24-0e4681f46e53%40isocpp.org.
Richard Hodges
2018-03-04 10:58:12 UTC
Permalink
For my part, while I think the general idea is a good one, it seems to me
that you will make a stronger argument if you are able to provide
motivating use-cases to strengthen the argument for each type/template.

Do you have some examples?
Post by Vincent Reverdy
Hey,
I was starting to think about putting together a proposal to add minor
helper classes to either type_traits/utility/tuple to help with some of the
operations done again and again when doing template metaprogramming.
Here is a list of a few I can think of, but I would have liked to hear
other suggestions. Names are just indicative, and bikeshedding would happen
for all of these types.
- *std::blank*, defined as an empty struct
struct blank{};
- *std::pack*, to hold a parameter pack of type
template <class... T> struct pack{};
- *std::convertible*, a type convertible to anything
struct convertible{template <class T> constexpr operator T() const
noexcept;};
- *std::copy_qualifiers*, a type traits copying ref and cv qualifiers
from one type to another
template <class From, class To> struct copy_qualifiers {using type = /*
cv-ref qualfiers of From applied to To*/;};
Other suggestions?
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit https://groups.google.com/a/
isocpp.org/d/msgid/std-proposals/e3415a75-7e20-48dd-
9e24-0e4681f46e53%40isocpp.org
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/e3415a75-7e20-48dd-9e24-0e4681f46e53%40isocpp.org?utm_medium=email&utm_source=footer>
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALvx3hacsACYSq%2Bh7BHNCjZ2rpajbdcBxa8GigKuHnjO79YDyQ%40mail.gmail.com.
Gašper Ažman
2018-03-04 11:21:23 UTC
Permalink
I call copy_qualifiers "like" in the deducing this paper. I plan to
propose it in a separate library extension paper along with forward_like.

I like your other proposals. Also see the std::type discussion around the
std;:identity paper, I forget the number, by Timur.

G
Post by Richard Hodges
For my part, while I think the general idea is a good one, it seems to me
that you will make a stronger argument if you are able to provide
motivating use-cases to strengthen the argument for each type/template.
Do you have some examples?
Post by Vincent Reverdy
Hey,
I was starting to think about putting together a proposal to add minor
helper classes to either type_traits/utility/tuple to help with some of the
operations done again and again when doing template metaprogramming.
Here is a list of a few I can think of, but I would have liked to hear
other suggestions. Names are just indicative, and bikeshedding would happen
for all of these types.
- *std::blank*, defined as an empty struct
struct blank{};
- *std::pack*, to hold a parameter pack of type
template <class... T> struct pack{};
- *std::convertible*, a type convertible to anything
struct convertible{template <class T> constexpr operator T() const
noexcept;};
- *std::copy_qualifiers*, a type traits copying ref and cv qualifiers
from one type to another
template <class From, class To> struct copy_qualifiers {using type = /*
cv-ref qualfiers of From applied to To*/;};
Other suggestions?
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/e3415a75-7e20-48dd-9e24-0e4681f46e53%40isocpp.org
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/e3415a75-7e20-48dd-9e24-0e4681f46e53%40isocpp.org?utm_medium=email&utm_source=footer>
.
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALvx3hacsACYSq%2Bh7BHNCjZ2rpajbdcBxa8GigKuHnjO79YDyQ%40mail.gmail.com
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CALvx3hacsACYSq%2Bh7BHNCjZ2rpajbdcBxa8GigKuHnjO79YDyQ%40mail.gmail.com?utm_medium=email&utm_source=footer>
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAANG%3DkWYr4My4ocY37oi-Nk_paCCegG3LtngSz4Lp5SXpAWF8w%40mail.gmail.com.
Larry Evans
2018-03-05 08:16:57 UTC
Permalink
Post by Vincent Reverdy
Hey,
I was starting to think about putting together a proposal to add minor
helper classes to either type_traits/utility/tuple to help with some of the
operations done again and again when doing template metaprogramming.
Here is a list of a few I can think of, but I would have liked to hear
other suggestions. Names are just indicative, and bikeshedding would happen
for all of these types.
- *std::blank*, defined as an empty struct
struct blank{};
or:
using blank=std::tuple<>;
another name is unit:
https://en.wikipedia.org/wiki/Unit_type
Post by Vincent Reverdy
- *std::pack*, to hold a parameter pack of type
template <class... T> struct pack{};
- *std::convertible*, a type convertible to anything
struct convertible{template <class T> constexpr operator T() const
noexcept;};
- *std::copy_qualifiers*, a type traits copying ref and cv qualifiers
from one type to another
template <class From, class To> struct copy_qualifiers {using type = /*
cv-ref qualfiers of From applied to To*/;};
Other suggestions?
https://github.com/cppljevans/variadic_templates/blob/master/boost/mpl/while.hpp
https://github.com/cppljevans/variadic_templates/blob/master/boost/mpl/if_recur.hpp
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/p7iu9q%24c8r%241%40blaine.gmane.org.
Arthur O'Dwyer
2018-03-05 22:34:38 UTC
Permalink
Post by Vincent Reverdy
Hey,
I was starting to think about putting together a proposal to add minor
helper classes to either type_traits/utility/tuple to help with some of the
operations done again and again when doing template metaprogramming.
Here is a list of a few I can think of, but I would have liked to hear
other suggestions. Names are just indicative, and bikeshedding would happen
for all of these types.
- *std::blank*, defined as an empty struct
struct blank{};
`monostate`, `in_place_t`, `nothrow_t`, `void`, `nullptr_t`. I don't think
we should make any more synonyms for it without a very clear use-case. In
fact, `monostate` has a really clear and specific use-case and I *still*
don't think it should have been standardized.
Post by Vincent Reverdy
- *std::pack*, to hold a parameter pack of type
template <class... T> struct pack{};
Bikeshed: I spell this as `typelist<Ts...>`.
- *std::convertible*, a type convertible to anything
struct convertible{template <class T> constexpr operator T() const
noexcept;};
Consider whether you ever want
struct convertible2 {
template<class T> constexpr operator T&&() const noexcept;
};
and/or
struct convertible3 {
template<class T> explicit constexpr operator T() const noexcept;
};
and if so, how many types should be standardized. My instinct is not to
standardize this without both a clear use-case and some evidence that this
specific definition is necessary and sufficient to solve that use-case.
Post by Vincent Reverdy
- *std::copy_qualifiers*, a type traits copying ref and cv qualifiers
from one type to another
template <class From, class To> struct copy_qualifiers {using type = /*
cv-ref qualfiers of From applied to To*/;};
Bikeshed: You'll want all three of `std::copy_cv_t`,
`std::copy_reference_t`, `std::copy_cvref_t`.
Consider whether `copy_reference_t<int&&, int&>` should be `int&&` or
`int&`.
Consider whether `copy_reference_t<int, int&>` should be `int` or `int&`.
https://stackoverflow.com/questions/31171682/type-trait-for-copying-cv-reference-qualifiers

To your list of metaprogramming utilities I would add...

*std::priority_tag
<https://github.com/Quuxplusone/from-scratch/blob/master/include/scratch/bits/type-traits/priority-tag.h>*,
a type trait for creating ranked overload sets
template<size_t I> struct priority_tag : priority_tag<I-1> {};
template<> struct priority_tag<0> {};

*std::index_constant
<https://github.com/Quuxplusone/from-scratch/blob/master/include/scratch/bits/type-traits/integral-constant.h#L24>*,
a convenience alias for std::integral_constant (useful in the
implementation of std::variant's getters, for example)
template<size_t I> using index_constant = integral_constant<size_t, I>;

*std::false_v
<https://github.com/Quuxplusone/from-scratch/blob/master/include/scratch/bits/type-traits/false-v.h>*,
a convenience alias for false which is "dependent" in template contexts
(useful in static_asserts)
template<class...> inline constexpr bool false_v = false;

–Arthur
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/0411546e-b09b-4819-a970-0c809c030980%40isocpp.org.
f***@gmail.com
2018-03-08 10:36:02 UTC
Permalink
I really like this idea.

When writing template metaprograms, we always need roughly the same helpers.


- std::blank: why not, but I'm not sure it would be a good thing to have
a common name for many different purposes
- std::pack<T...>: Very useful, but I agree with Arthur, std::typelist
would probably be a better name. The thing with this one, we would need
some meta-functions to work with (like getting the n-th element, getting
the size, and other stuff like that). So I would say a full proposal only
for this one might be better.
- std::convertible: I'm not sure about the name here, it is too vague
and looks like a type trait
- std::copy_qualifiers: this one is great, but need some variants (like
Arthur said)
- std::priority_tag<size_t>: I would avoid this one: I completely
understand the use case, but this would incentivize people to use index
priority and the will use quite high priorities, and thus create a hell lot
of (useless) types. If there is another way to do it without relying on
inheritance (which will create all the higher priority types), then sure,
it would be a good idea.
- std::index_constant: yes, really simple, but would standardize a
common practice (maybe needs a shorter name?)
- std::false_v<...>: I agree it would be cool, but I'm not about the
interface... Could it be better if not using types as template parameters?


Now some more ideas:

- If you have std::false_v, you should also have std::true_v with the
same interface just for the sake of consistency
- std::sink
struct sink { template <class T> constexpr sink(T&&) noexcept {} };
std::sink is constructible from any expression.
- maybe we would also need to have something hybrid between std::sink
and std::convertible:
struct sink_convertible : sink, convertible { using sink::sink; };


- std::convertible_ptr
struct convertible_ptr { constexpr convertible operator*() noexcept {
return {}; } /* some functions to have iterator semantic */};
Like std::convertible, but with iterator semantic.

Florian
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/b184aa97-d05a-4f2f-9f53-b68550e57936%40isocpp.org.
Vincent Reverdy
2018-04-06 09:34:07 UTC
Permalink
Hello all,

Here is the current paper. Comments are welcome.
I didn't put things related to convertible/sink, because I think it
deserves its own paper.
For the typelist, I am expecting something along this line coming from SG7.
And for the priority_tag for overloads it will probably come in a later
proposal of mine.

Best,
Vincent
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/b2ecb2d3-4f2a-4d17-a9a9-eec3c51a71c3%40isocpp.org.
f***@gmail.com
2018-04-06 12:02:48 UTC
Permalink
Just a quick comment, what is the distinction between std::copy_* and
std::clone_*?
I think I understand the difference, but it is never stated in the document.

Also, I would not recommend to inherit from std::blank if the condition is
false in std::inherit_if<>. I would use an internal type that is not
accessible by the user.

Finally, I would probably recommend an extra one:
template <class T>
using inherit_if_valid = inherit_if<is_inheritable_v<T>, T>;
I think it will be a pretty common pattern.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/e1b23f7b-466a-49ed-844b-111411772cc8%40isocpp.org.
Vicente J. Botet Escriba
2018-04-06 15:37:46 UTC
Permalink
Post by Vincent Reverdy
Hello all,
Here is the current paper. Comments are welcome.
I didn't put things related to convertible/sink, because I think it
deserves its own paper.
For the typelist, I am expecting something along this line coming from SG7.
And for the priority_tag for overloads it will probably come in a
later proposal of mine.
Hi Vincent,

are you working on some improvement to std::overload [P0051R0]?

Associated to the copy_/clone_ transformation traits I have needed often
a rebind which has similar use cases (See P0343R1
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0343r1.pdf>)

BTW, What is the difference between is_functor and is_function_object?
Having the test of the standard could help.

When do you need to use is_closure?

For type_t, false_v, .... I read the  Arthur O’Dwyer's blog. I believe
the paper should be more specific about the example so that people are
not required to read the blog (which btw it is iteresting).

Best,
Vicente

BTW, the links of the references are broken (no link at all).
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/90b61131-1000-f81e-14bf-30f85283c504%40wanadoo.fr.
Nicol Bolas
2018-04-06 16:50:54 UTC
Permalink
Post by Vincent Reverdy
Hello all,
Here is the current paper. Comments are welcome.
I didn't put things related to convertible/sink, because I think it
deserves its own paper.
For the typelist, I am expecting something along this line coming from SG7.
And for the priority_tag for overloads it will probably come in a later
proposal of mine.
In the function traits, there seem to be some superfluous ones. Or at
least, things that need to have motivation applied to them.

`is_callable` is useful primarily as a component of other traits.

`is_functor` is really just the intersection of `is_class||is_union` and
`is_callable`. But this is really the wrong intersection. The principle
motivational use for `is_functor` would be for something like
`std::overload`, whose types must be classes and callable. But the thing
is, `std::overload`'s callable types must be *inheritable*, since that's
how `std::overload` implements stuff. So `std::overload` would really be
using `is_callable` and `is_inheritable` to guard the types it is provided.

So, can you provide a use case for `is_functor`, where code can accept
*any* class with an overloaded `operator()`, even if it cannot inherit from
it? If not, then this is not needed.

`is_function_object` seems dubious. See, the most useful place one might
see it is in algorithms. But quite frankly, algorithms ought to be adjusted
to use `std::invoke`, so that they can take member pointers too.

So, can you provide a use case for an interface that *should* explicitly
exclude member pointers?

`is_closure` seems not just useless but anti-useful. Closures and lambdas
are nothing more than syntactic sugar. Any interface that accepts a lambda
ought to also be able to accept a user-defined class type. To do otherwise
creates a user-hostile interface; we *don't want* users to be able to
restrict interfaces in this way.

Can you provide a use case for this trait that doesn't make the interface
actively worse than using `is_functor`?
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/08cab291-d82d-4620-a825-6331deafc8fa%40isocpp.org.
Vicente J. Botet Escriba
2018-04-07 07:49:26 UTC
Permalink
Post by Vincent Reverdy
Hello all,
Here is the current paper. Comments are welcome.
I didn't put things related to convertible/sink, because I think
it deserves its own paper.
For the typelist, I am expecting something along this line coming from SG7.
And for the priority_tag for overloads it will probably come in a
later proposal of mine.
In the function traits, there seem to be some superfluous ones. Or at
least, things that need to have motivation applied to them.
`is_callable` is useful primarily as a component of other traits.
`is_functor` is really just the intersection of `is_class||is_union`
and `is_callable`. But this is really the wrong intersection. The
principle motivational use for `is_functor` would be for something
like `std::overload`, whose types must be classes and callable. But
the thing is, `std::overload`'s callable types must be /inheritable/,
since that's how `std::overload` implements stuff. So `std::overload`
would really be using `is_callable` and `is_inheritable` to guard the
types it is provided.
Right. My implementation checks only for the is_inheritable part. The
callable part is checked when calling it :(
Having a is_callable could help, to diagnose as soon as possible when
when overload takes something that is not callable, but this doesn't
mean that it is callblae with the arguments it will be called.
Is when we call it that we really check for the Callable.
To be pedantic, we need is_callable, but from the pragmatical point of
view, it is is_invocable that is useful.
BTW, We need that std::invoke is contexpr. Was this fixed already?
Post by Vincent Reverdy
So, can you provide a use case for `is_functor`, where code can accept
*any* class with an overloaded `operator()`, even if it cannot inherit
from it? If not, then this is not needed.
`is_function_object` seems dubious. See, the most useful place one
might see it is in algorithms. But quite frankly, algorithms ought to
be adjusted to use `std::invoke`, so that they can take member
pointers too.
So, can you provide a use case for an interface that /should/
explicitly exclude member pointers?
`is_closure` seems not just useless but anti-useful. Closures and
lambdas are nothing more than syntactic sugar. Any interface that
accepts a lambda ought to also be able to accept a user-defined class
type. To do otherwise creates a user-hostile interface; we /don't
want/ users to be able to restrict interfaces in this way.
Can you provide a use case for this trait that doesn't make the
interface actively worse than using `is_functor`?
Agreed for all the comments. We need use cases.

However I will not be against (your approach Vincent) to request traits
for everything defined in the standard. But if we don't have use cases
for those traits, we don't need to spend time on them.

Vicente
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/9af6e244-f79c-db67-70a1-165a95780f4f%40wanadoo.fr.
Arthur O'Dwyer
2018-04-06 20:04:03 UTC
Permalink
Post by Vincent Reverdy
Hello all,
Here is the current paper. Comments are welcome.
I didn't put things related to convertible/sink, because I think it
deserves its own paper.
For the typelist, I am expecting something along this line coming from SG7.
And for the priority_tag for overloads it will probably come in a later
proposal of mine.
On inherit_if<T>: I would remove or significantly rework this part.
- What's the use-case? Given that [[no_unique_address]] is coming to deal
with EBO, do we *have* a use-case anymore?
- is_inheritable<T> sounds useful at first but is likely to be
unimplementable in any actually useful way. Should it yield false for
classes with private destructors? Deleted move operations? What else?
- You show an example of a class inheriting from an integral type, which is
forbidden.
- You seem to suggest that inherit_if_t<B, T> should be exactly
conditional_t<B, T, blank>, which (A) is not a significant savings and (B)
does not permit multiple inheritance from several different "falsey"
inherit_if_ts.

template<class... Ts> struct NaiveCompressedTuple :
inherit_if_t<is_inheritable_v<Ts>, Ts> {};
NaiveCompressedTuple<int, short> x; // fails to compile because you
can't inherit twice from std::blank

I believe there are enough problems with inherit_if, and enough better
solutions in the pipeline, that you should rip it out of your proposal.

I don't object to `std::blank` in principle, but with `inherit_if` gone you
have no more use-cases for `blank` and so it should go as well, or else you
should add more motivation for it.

On remove_all_pointers: The use-case for remove_all_extents is to take a
possibly-array type and boil it down to a non-array type with the same
copyability/destructibility properties, for the specific purpose of
computing those properties. I don't believe you have any use-case for
remove_all_pointers.
Philosophically, you need to explain why you feel the need for
remove_all_extents and remove_all_pointers, but you don't feel the need for
remove_all_extents_and_pointers (which would be able to boil `int *(*)[5]`
down to just `int`).

Philosophically, you need to explain why you desire this behavior:
using A = int;
using B = double;
using C = double*;
static_assert(is_same_v<clone_all_pointers_t<A**, B**>, B**>);
static_assert(is_same_v<clone_all_pointers_t<A**, C**>, C*>); // EEK!
I claim that you *don't* desire this behavior, that you have no use-case
for this foo_all_pointers stuff, and you should just rip it out of the
proposal.

On copy_x and clone_x: Anecdotally, I have done a similar thing for cvref
qualifiers in some codebase, and then discovered that there was a much
better solution that didn't involve copying cvref qualifiers.
- Nit: When there are two options T/F, I'm used to them coming in that
order and with the obvious meanings. Please write out "From" and "To"
instead of "F" and "T".
- So, for 'x' in {const, volatile, pointer}, we have
template<From, To> using copy_x = conditional_t<is_x<From>, add_x<To>,
To>;
template<From, To> using clone_x = copy_x<From, remove_x<To>>;
And then we have some more general helpers {cv, reference, extent} and some
wacky ones {pointers, extents}.

I am mildly uncomfortable with the existence of *both* copy_x and clone_x.
If you provided only copy_x, how much extra typing would the user have to
do to get the effect of clone_x? If you provided only clone_x, how much
extra typing would the user have to do to get the effect of copy_x? I'd
like to see a discussion with examples, in the paper.

You should remove the discussion of the behavior of "hypothetical
clone_signedness." Don't waste my brain's time thinking about it; just say
why you're not proposing it and move on.

In exchange for all the stuff I'm saying is flawed and needs to go... I
think you should go ahead and include `priority_tag`. If someone else is
proposing it as well, that's cool; just try to make sure you're putting it
in the same place as them, so there's no merge conflict.

HTH,
Arthur
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0%2Bec8YaKSc7DUo8R7GwHJ_EKr92WOTu%2BtR4suV-cr4G8Q%40mail.gmail.com.
Nicol Bolas
2018-04-06 20:22:36 UTC
Permalink
Post by Arthur O'Dwyer
Post by Vincent Reverdy
Hello all,
Here is the current paper. Comments are welcome.
I didn't put things related to convertible/sink, because I think it
deserves its own paper.
For the typelist, I am expecting something along this line coming from SG7.
And for the priority_tag for overloads it will probably come in a later
proposal of mine.
On inherit_if<T>: I would remove or significantly rework this part.
- What's the use-case? Given that [[no_unique_address]] is coming to deal
with EBO, do we *have* a use-case anymore?
So long as this is possible:

template<typename ...Ts>
class something : Ts... {...};

And this isn't:

template<typename ...Ts>
class something
{
Ts ts...;
};

There's a use case for it.

Granted, I would *much rather* have the latter, but that's a huge can of
worms.
Post by Arthur O'Dwyer
- is_inheritable<T> sounds useful at first but is likely to be
unimplementable in any actually useful way. Should it yield false for
classes with private destructors? Deleted move operations? What else?
- You show an example of a class inheriting from an integral type, which
is forbidden.
- You seem to suggest that inherit_if_t<B, T> should be exactly
conditional_t<B, T, blank>, which (A) is not a significant savings and (B)
does not permit multiple inheritance from several different "falsey"
inherit_if_ts.
inherit_if_t<is_inheritable_v<Ts>, Ts> {};
NaiveCompressedTuple<int, short> x; // fails to compile because you
can't inherit twice from std::blank
That's a good point. If you've got a bunch of `Ts`, you'd have to do
something like `std::conditional_t<is_inheritable<Ts>, Ts,
std::blank<index_of<Ts>>>...`, where `index_of<Ts>` gets the index for the
particular `Ts` in the expansion.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/fcb9d6d5-a7bf-4442-9df3-4d112596e6be%40isocpp.org.
Vicente J. Botet Escriba
2018-04-07 07:20:16 UTC
Permalink
Post by Vincent Reverdy
Hello all,
Here is the current paper. Comments are welcome.
I didn't put things related to convertible/sink, because I
think it deserves its own paper.
For the typelist, I am expecting something along this line coming from SG7.
And for the priority_tag for overloads it will probably come
in a later proposal of mine.
On inherit_if<T>: I would remove or significantly rework this part.
- What's the use-case? Given that [[no_unique_address]] is coming
to deal with EBO, do we /*have*/ a use-case anymore?
|
template<typename...Ts>
classsomething :Ts...{...};
|
|
template<typename...Ts>
classsomething
{
Tsts...;
};
|
There's a use case for it.
I'm not sure.
Post by Vincent Reverdy
Granted, I would /much rather/ have the latter, but that's a huge can
of worms.
- is_inheritable<T> sounds useful at first but is likely to be
unimplementable in any actually useful way. Should it yield false
for classes with private destructors? Deleted move operations?
What else?
This is why we need it and provided by the compiler.
IMO, it should result in false when you can not inherit from, for
whatever reason.
If the compiler have already a reason why

struct D : T {};

is ill formed, the traits must yield false.

This doesn't mean that the wording shouldn't be explicit.
Post by Vincent Reverdy
- You show an example of a class inheriting from an integral type,
which is forbidden.
- You seem to suggest that inherit_if_t<B, T> should be exactly
conditional_t<B, T, blank>, which (A) is not a significant savings
and (B) does not permit multiple inheritance from several
different "falsey" inherit_if_ts.
inherit_if_t<is_inheritable_v<Ts>, Ts> {};
    NaiveCompressedTuple<int, short> x;  // fails to compile
because you can't inherit twice from std::blank
That's a good point. If you've got a bunch of `Ts`, you'd have to do
something like `std::conditional_t<is_inheritable<Ts>, Ts,
std::blank<index_of<Ts>>>...`, where `index_of<Ts>` gets the index for
the particular `Ts` in the expansion.
The problem is that usually, when you cannot inherit, you need to wrap
the Callable and inherit.
Vincent, what is the use case  for inherit_if? What the user want if not?


Vicente
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/fba740f1-66a6-badf-0b44-9b92bcf75777%40wanadoo.fr.
Vincent Reverdy
2018-04-06 12:37:38 UTC
Permalink
Stated on the top of page 3:
The difference is that the copiers directly copy the qualifiers of the
first argument to the second, while cloners first discard the qualifiers of
the second argument. For example copy_cv_t<volatile int, const
double>evaluates to const volatile double while clone_cv_t<volatile int,
const double> evaluates to volatile double, and copy_all_pointers_t<int***,
double*> evaluates to double**** while clone_all_pointers_t<int***,
double*> evaluates to double***.

And thanks for the other remarks!
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ae303c7d-ab2e-4dd4-b7a3-416a1f97ceee%40isocpp.org.
f***@gmail.com
2018-04-06 12:57:06 UTC
Permalink
Indeed, I missed it...

Now I wonder. What does happen if pointers are cv-qualified?
using T = copy_all_pointers_t<const int*const*const, float>;
// T is const float*const*const
// or T is float*const*const
// or T is float*const*
// or T is float**

I'm pretty sure the inner cv-qualifiers should be copied. I'm also quite
confident that the most inner cv-qualifier should be discarded.
What about the outer cv-qualifiers?
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/aacca2ae-b51c-4dc7-ae96-c23a1f47f2d7%40isocpp.org.
Vincent Reverdy
2018-04-06 13:16:37 UTC
Permalink
It's an open question that will be ask to LEWG. For now the behavior is
that it copies pointers and their qualification (in the same way
remove_pointer removes pointers and their qualification).
So T is float*const*const
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/619b9207-cd1c-4e1e-be6b-b9dcb5116ab6%40isocpp.org.
Vincent Reverdy
2018-04-06 16:05:24 UTC
Permalink
@Vicente

Hi Vicente,

Yes, I am working on an update and improvement of the overload proposal. It
will be in 3 parts (independent, but related)

- New type traits: this one
- A std::functor class
- Classes to create custom overload set and sequences (+ new very useful
and weird metaprogramming tricks based on that)

I will look closely to P0343R1. In the standard, a pointer to function is
considered to be a function object. That's why I propose to have is_functor
and is_function_object (more details here
<https://stackoverflow.com/questions/49503229/are-function-pointers-function-objects-in-c>
).

For the broken links, sorry.

Best,
Vincent
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/7c8f2068-5434-4294-a3ab-0691dc39b6c1%40isocpp.org.
Vicente J. Botet Escriba
2018-04-07 07:35:39 UTC
Permalink
Post by Vincent Reverdy
@Vicente
Hi Vicente,
Yes, I am working on an update and improvement of the overload
proposal. It will be in 3 parts (independent, but related)
* New type traits: this one
* A std::functor class
Could you tell us more?
Post by Vincent Reverdy
* Classes to create custom overload set and sequences (+ new very
useful and weird metaprogramming tricks based on that)
How your paper would improve p0051? What is the idea? I'm asking for
that because we don't have yet wording for std::overload.
You can check the last draft at
https://github.com/viboes/tags/blob/master/doc/proposals/overload/p0051r4.md.
Post by Vincent Reverdy
I will look closely to P0343R1. In the standard, a pointer to function
is considered to be a function object. That's why I propose to have
is_functor and is_function_object (more details here
<https://stackoverflow.com/questions/49503229/are-function-pointers-function-objects-in-c>).
is_functor will be equivalent to is_function_object and is_class?
As "functor" doesn't appear in the standard, I would suggest to we look
for another name.
Lets reserve "functor" for functors in the category theory (functors,
applicatibles, monads) (See
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0650r2.pdf)
Post by Vincent Reverdy
For the broken links, sorry.
It would help the reading ;-)


Best,
Vicente
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c5985c54-1474-7ff2-7a09-96240779f92b%40wanadoo.fr.
Vincent Reverdy
2018-04-08 09:42:05 UTC
Permalink
Thanks all for the feedback.

I will work far more on use cases and will try to provide examples for
every single type trait. All these type traits have motivations:

- either I have had several use cases for them in my own code base
- or they are here for completeness because of a similar trait falls
into the previous bullet point

@Arthur O'Dwyer:
Thanks for the feeback on the inherit_* thingy. I will completely rework
this part (because I still think these are useful traits).

For the "priority tag", I need to see first, how it interacts with the
overload proposal I am working on. I have used such a tool before (under
the name of "overload_rank"). But if you want to proceed and write a paper
with the wording without waiting on me, I will definitely vote for it,
because I've had a lot of use cases.

@Vicente:
The details about the two other proposals will come (hopefully before
Rapperswill), but I have a lot on my plate right now. My idea is to split
the problem about overload in first having a way to transform any callable
into an inheritable class with a function call operator (an improved
std::function), and have the overload proposal relying on it. Currently I
have no magical technique for non-inheritable classes, BUT, if we have the
overload tools relying on the function call operator proposal, then it
becomes the problem of the function call operator proposa (which will have
a far less large scope than the overload proposal)l. And my guess is that
reflection will provide us a way to deal with non-inheritable classes. I
promise more details will come with time.

(As a note, I am looking far more for constructive feedback (ie how the
current version can be improved) than on "this is bullshit and useless and
this part should be riped appart" comments. I don't necessarily disagree
whether a part is not that relevant, but there are standpoints in between
"this can be improved" and "this is complete bullshit". It's not because
someone never had a use case, that others haven't. Also, if you think that
something else should be included, feel free to write motivations, use
cases and wording. Help is very welcome! Thank you very much!)
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/b857bf08-6f01-475c-a458-72dda248415e%40isocpp.org.
f***@gmail.com
2018-04-09 09:49:08 UTC
Permalink
On the inheritance, a while ago, I was thinking about having the
possibility to inherit from a non-class type.
I don't think we need to change the language for that, but we could have
access to a way to transform any non-class type into a class type.

For this, let me introduce the object metafunction:
template <class T>
using object = /* implementation defined */;

I think this could be naively implemented like this:
template <class T>
class objectified;

template <>
class objectified<int> {
private:
int data;
public:
objectified() = default;
objectified(const objectified&) = default;
objectified& operator=(const objectified&) = default;
~objectified() = default;

objectified(int data) : data(data) {}
operator const int&() const& { return data; }
operator const int&&() const&& { return data; }
operator int&() & { return data; }
operator int&&() && { return data; }

/* implements all operations supported by int */
};
// other specializations

template <class T>
struct objectify {
using type = T;
};
template <>
struct objectify<int> {
using type = objectified<int>;
};
// other specializations

template <class T>
using object = typename objectify<T>::type;

With that, you don't need a special case when you need to inherit from a
non-class type:
template <class T>
class proxy : std::object<T> { /* whatever */ };

If T is a class, then std::object<T> is T.
Otherwise, it is a type with the same behavior (at least what is actually
achievable with a class).
Of course, this could be implemented in a much more generic way, not
relying on specializing for every single literal type.


Concerning the priority_tag, we need to be careful how it is implemented
(inheritance will blow up compilation time for extreme priorities).
So I don't know how to implement it while avoiding long compilations...
In that respect, overload_rank could much easier to implement
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c02a5596-ff2b-4a51-b01f-3544255ddeb9%40isocpp.org.
Arthur O'Dwyer
2018-04-09 18:40:04 UTC
Permalink
Post by f***@gmail.com
Concerning the priority_tag, we need to be careful how it is implemented
(inheritance will blow up compilation time for extreme priorities).
So I don't know how to implement it while avoiding long compilations...
In that respect, overload_rank could much easier to implement
Can you post the implementation of overload_rank that you're thinking of?
In a quick Google search for "overload_rank c++", I found only this
overload_rank<K>
<https://stackoverflow.com/questions/42044116/no-matching-function-stdforward-with-lambdas>
which is identical to priority_tag<K>, and this rank<K>
<http://detercode121.blogspot.com/2011/07/c-can-overloads-for-generic-functions.html>
which is also identical to priority_tag<K>.

template<size_t K> struct priority_tag : priority_tag<K-1> {};
template<> struct priority_tag<0> {};

As for "extreme priorities", notice that the former link's code dispatches
on overload_rank<5> and the latter's dispatches on rank<256>, and neither
writer cares to talk about compilation overhead (because it is negligible).
Instantiating even 256 empty struct types is child's play to a compiler
that can easily compile programs with literally *thousands* of functions.
However, when I use priority_tag<K>, I am generally careful to use the
lowest priorities that get my job done correctly — more out of a sense of
self-documenting code, than out of a concern for efficiency.

–Arthur
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0JYFTKiROEnLRyEdgOQbopGwFRbtMurqd6tuTfJsjxbsQ%40mail.gmail.com.
f***@gmail.com
2018-04-10 09:52:13 UTC
Permalink
First, about the priority_tag: the problem is not that you will use
priority_tag<10000> (because you won't), but beginners will do.
It's true that it's fast to compile (at least for 900), but at some point,
you get a compiler error because it tries to instantiate more nested
templates than their own limit (900 for GCC by default).
So if you use an extreme priority like 800, and you use it in heavily
templated code, you might reach this limit without even thinking about it.

About overload_rank, I might have misunderstood what it actually is.
So let me give what I understood:

template <class... Fs>
class overload_rank {};

template <class F, class... Fs>
class overload_rank<F, Fs...> : overload_rank<Fs...> {
private:
F f;
overload_rank<Fs...>& base() { return *this; }
public:
overload_rank(F f, Fs... fs) : overload_rank<Fs...>(std::move(fs)...), f
(std::move(f)) {}
overload_rank(const overload_rank &) = default;
overload_rank( overload_rank&&) = default;
overload_rank& operator=(const overload_rank &) = default;
overload_rank& operator=( overload_rank&&) = default;
~overload_rank() = default;

// This is the prefered overload as it is constrained
template <class... Args>
requires requires(F f){ f(std::declval<Args&&>()...); }
decltype(auto) operator()(Args&&... args)
noexcept(noexcept(f(std::forward<Args>(args)...))) {
return f(std::forward<Args>(args)...);
}

template <class... Args>
decltype(auto) operator()(Args&&... args)
noexcept(noexcept(base()(std::forward<Args>(args)...))) {
return base()(std::forward<Args>(args)...);
}
};

Here is a use example:
auto g(void*) { return "void*"; }
auto g(int) { return "int"; }

overload_rank f{[](void*){ return "void*"; }, [](int){ return "int"; }};
f(0); // -> "void*"
//g(0); // ambiguous overload

Writing this, I realize this is not really an overload_rank, but an
ordered_overload.
Back to the point: this class is easily implementable with any priority_tag.
But that might not be the same thing as you designed by overload_rank.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/dff5a752-a7fe-47de-9ca0-4771c41b6c54%40isocpp.org.
Iván Sanz
2018-04-09 09:55:22 UTC
Permalink
std::never would be really useful when working with SFINAE to avoid two
fase lookup
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADhC_A1KJr%2BuwPPgs0vk-tA20MZXB9f_vwStFufuGRnG5Og9hg%40mail.gmail.com.
Vincent Reverdy
2018-04-09 12:14:03 UTC
Permalink
Could you explain in more details, what std::never would be?
(declaration/definition)
Post by Iván Sanz
std::never would be really useful when working with SFINAE to avoid two
fase lookup
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/b69d44eb-00f2-4885-80f8-979602bd64d1%40isocpp.org.
b***@gmail.com
2018-04-10 07:43:57 UTC
Permalink
It could be as simple as this:

template<typename...>
struct never;

This is very helpful when voiding two phase lookup:

// this can be optimized by the compiler as "false_type" doesn't depend on
anything
template<typename...>
struct always_false : std::false_type { };

// this forces compiler to not optimize it
template<>
struct force_false<std::never<>> : std::true_type { };
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/3664c080-f445-429d-96e7-78db2fb35e46%40isocpp.org.
Iván Sanz
2018-04-10 07:45:26 UTC
Permalink
It could be as simple as this:

template<typename...>
struct never;

This is very helpful when voiding two phase lookup:

// this can be optimized by the compiler as "false_type" doesn't depend on
anything
template<typename...>
struct always_false : std::false_type { };

// this forces compiler to not optimize it
template<>
struct force_false<std::never<>> : std::true_type { };
Post by Vincent Reverdy
Could you explain in more details, what std::never would be?
(declaration/definition)
Post by Iván Sanz
std::never would be really useful when working with SFINAE to avoid two
fase lookup
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ef3507ba-609a-4c67-9149-338ebfc433a7%40isocpp.org.
Vincent Reverdy
2018-04-10 17:40:51 UTC
Permalink
@Ivan:

I'm not sure I understand correclty.
Would this bring anything more than:

template <class...> using void_t = void; // Already included in C++17
template <class...> inline constexpr bool false_v = false; // Already
included in the proposal
template <class...> inline constexpr bool true_v = true; // Already
included in the proposal

and if so, what?
Thanks!
Post by b***@gmail.com
template<typename...>
struct never;
// this can be optimized by the compiler as "false_type" doesn't depend on
anything
template<typename...>
struct always_false : std::false_type { };
// this forces compiler to not optimize it
template<>
struct force_false<std::never<>> : std::true_type { };
Post by Vincent Reverdy
Could you explain in more details, what std::never would be?
(declaration/definition)
Post by Iván Sanz
std::never would be really useful when working with SFINAE to avoid two
fase lookup
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/52b67400-9e4e-41e1-a027-aa0b0cb4e8cf%40isocpp.org.
Arthur O'Dwyer
2018-04-10 18:05:56 UTC
Permalink
Post by Vincent Reverdy
I'm not sure I understand correclty.
template <class...> using void_t = void; // Already included in C++17
template <class...> inline constexpr bool false_v = false; // Already
included in the proposal
template <class...> inline constexpr bool true_v = true; // Already
included in the proposal
and if so, what?
Thanks!
Post by b***@gmail.com
template<typename...>
struct never;
// this can be optimized by the compiler as "false_type" doesn't depend
on anything
template<typename...>
struct always_false : std::false_type { };
This smells like a misunderstanding of what the compiler is allowed to do,
at least as of C++17. In C++17 and later (and in practice earlier as well,
AFAIK), the compiler is *forbidden* to compile the following program:

template<class...> using void_t = void; // part of the C++17 standard
library

template<class T> void must_sfinae(T t) -> void_t<typename
T::value_type> {}

int main() {
must_sfinae(1); // must SFINAE away, must not simply return void
}

Ivan, if you know of a compiler that miscompiles this program today, please
tell us about it!

–Arthur

P.S.: libc++ has a helper type called `__nat` ("not a type") that is used
in metaprogramming; but I don't know anything about how it's used. A quick
peek tells me it's not much like Ivan's "std::never", despite the
superficially similar name.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0LskSA_zYSPhhKmTmYSGqnJyT4KNEp89cYzi0rufOhGWA%40mail.gmail.com.
Iván Sanz
2018-04-10 19:03:42 UTC
Permalink
I'll try to explain the problem in a simple way.

Imagine that you are doing SFINAE with lambdas, so you created this struct
to handle all the overloads:

template<typename... TOverload>
struct sfinae_lambda : TOverload...
{
constexpr sfinae_lambda(TOverload... overloads)
: TOverload(overloads)...
{}

using TOverload::operator()...;
};


template<typename... TOverloads>
constexpr auto make_sfinae_lambda(TOverloads... overloads)
{
return sfinae_lambda<TOverloads...>(overloads...);
}

It could be used like this:

constexpr auto overload0 = [](int x) { return "int"; };
constexpr auto overload1 = [](const char* s) { return "const char*"; };
constexpr auto overloaded_lambda = make_sfinae_lambda(overload0, overload1);

cout << overloaded_lambda(123) << endl; // int
cout << overloaded_lambda("hello!") << endl; // const char*
cout << overloaded_lambda(vector<int>{1, 2, 3}) << endl; // really nasty
compilation error!!!

Now our goal is to customize the compilation error to be something like:
"no possible overload found". How to do it?
Let's add a new method to our sfinae_lambda:

template<typename... TArgs>
constexpr auto operator()(TArgs&&... args) const
{
// force compilation error if compiler gets here
static_assert(false, "no possible overload found");
}

Nice idea, but it doesn't work. Why? the compiler isn't even waiting until
it gets into this method to compile our assert, it optimizes and
precompiles the body because of the two phase lookup. What does this mean?
If the assertion doesn't depend on any unknown type, it can be optimized
and triggered before knowing it. This breaks our nice solution. How to fix
it? let's make it depend on the parameter types!

// always false, ignore template types
template<typename...>
struct always_false : std::false_type { };

...

template<typename... TArgs>
constexpr auto operator()(TArgs&&... args) const
{
// force compilation error if compiler gets here
static_assert(
always_false<decltype(args)...>::value,
"no possible overload found");
}

Aaand... this works on current GCC and CLANG! but from the standard point
of view, this can also be optimized by the compilers, the thing is that
they are not as smart (right now, give them some time).
Then, how to make it so the standard forbids it to be optimized? Creating a
valid specialization inherits true_type! But what can we put in there? this
must be something that people will *never *pass in there.
Solution?

template<typename...>
struct never;

// and the specialization to explicity specify that this will never be true
(but disallow compiler optimizations)
template<>
struct always_false<std::never<>> : std::true_type { };

Wow, this was nice to write.
*The whole proof of concept can be found here: https://godbolt.org/g/SbtXWA
<https://godbolt.org/g/SbtXWA>*

std::never gives us the possibility to have a type provided by the standard
that will never be instantiated/used.
Post by Arthur O'Dwyer
Post by Vincent Reverdy
I'm not sure I understand correclty.
template <class...> using void_t = void; // Already included in C++17
template <class...> inline constexpr bool false_v = false; // Already
included in the proposal
template <class...> inline constexpr bool true_v = true; // Already
included in the proposal
and if so, what?
Thanks!
Post by b***@gmail.com
template<typename...>
struct never;
// this can be optimized by the compiler as "false_type" doesn't depend
on anything
template<typename...>
struct always_false : std::false_type { };
This smells like a misunderstanding of what the compiler is allowed to do,
at least as of C++17. In C++17 and later (and in practice earlier as well,
template<class...> using void_t = void; // part of the C++17 standard
library
template<class T> void must_sfinae(T t) -> void_t<typename
T::value_type> {}
int main() {
must_sfinae(1); // must SFINAE away, must not simply return void
}
Ivan, if you know of a compiler that miscompiles this program today,
please tell us about it!
–Arthur
P.S.: libc++ has a helper type called `__nat` ("not a type") that is used
in metaprogramming; but I don't know anything about how it's used. A quick
peek tells me it's not much like Ivan's "std::never", despite the
superficially similar name.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/69efc05e-8704-4161-a0f0-263a64ab53bd%40isocpp.org.
Iván Sanz
2018-04-10 19:08:15 UTC
Permalink
Sorry, the compiler output doesn't properly work in that link.
*This is the correct one: https://godbolt.org/g/s2hPVJ
<https://godbolt.org/g/s2hPVJ>*
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/4f5bc68f-8007-40a7-b3af-780f738c9be7%40isocpp.org.
Arthur O'Dwyer
2018-04-10 19:39:39 UTC
Permalink
Post by Iván Sanz
// always false, ignore template types
template<typename...>
struct always_false : std::false_type { };
...
template<typename... TArgs>
constexpr auto operator()(TArgs&&... args) const
{
// force compilation error if compiler gets here
static_assert(
always_false<decltype(args)...>::value,
"no possible overload found");
}
Simpler, and already part of the proposal:

template<typename... TArgs>
constexpr auto operator()(TArgs&&... args) const
{
// force compilation error if compiler gets here
static_assert(
std::false_v<TArgs...>,
"no possible overload found");
}

See also https://quuxplusone.github.io/blog/2018/04/02/false-v/
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0J_T6Ndx5keFixv5s%2BQ1BBqAP9EAoukTPaJDwZybzp6ig%40mail.gmail.com.
Barry Revzin
2018-04-10 19:48:31 UTC
Permalink
Post by Iván Sanz
// always false, ignore template types
template<typename...>
struct always_false : std::false_type { };
...
template<typename... TArgs>
constexpr auto operator()(TArgs&&... args) const
{
// force compilation error if compiler gets here
static_assert(
always_false<decltype(args)...>::value,
"no possible overload found");
}
Aaand... this works on current GCC and CLANG! but from the standard point
of view, this can also be optimized by the compilers, the thing is that
they are not as smart (right now, give them some time).
Then, how to make it so the standard forbids it to be optimized? Creating
a valid specialization inherits true_type! But what can we put in there?
this must be something that people will *never *pass in there.
Solution?
No, it cannot be "optimized by the compilers." This is a dependent value,
and there is always the potential that a hypothetical specialization of
always_false *could exist* somewhere, in some other code, that may or may
not be included before this by a user. You do not actually have to create
such a specialization yourself to prevent this from happening. Indeed, it
would be actively counterproductive for you to do so since suddenly your
always_false isn't actually always false.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/61c8450d-4585-4275-acee-6ddc56fb73f3%40isocpp.org.
Iván Sanz
2018-04-10 20:02:32 UTC
Permalink
Post by Iván Sanz
template<typename... TArgs>
constexpr auto operator()(TArgs&&... args) const
{
// force compilation error if compiler gets here
static_assert(
std::false_v<TArgs...>,
"no possible overload found");
}
Interesting, didn't hear about this one, thanks.

No, it cannot be "optimized by the compilers." This is a dependent value,
Post by Iván Sanz
and there is always the potential that a hypothetical specialization of
always_false *could exist* somewhere, in some other code, that may or may
not be included before this by a user. You do not actually have to create
such a specialization yourself to prevent this from happening. Indeed, it
would be actively counterproductive for you to do so since suddenly your
always_false isn't actually always false.
Right, I didn't even think about the fact that you can "specialize
anything, anywhere". Cool, this reduces the complexity a lot, thanks.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/12c01635-16fd-4901-942c-71d63071ac1a%40isocpp.org.
Vincent Reverdy
2018-04-11 10:34:36 UTC
Permalink
@Florian and Arthur O'Dwyer:

To me overload_rank is just the same thing as priority_tag with a different
name. The overload_rank you had in mind was more what I call an
overload_sequence. All of this will come, but in another proposal focused
on overloading. For now, I'll focus on the fundamental metaprogramming
utilities I needed.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/d8fbffa8-f9e9-4d60-b956-cf2c5556f314%40isocpp.org.
Loading...