Is there any proposal in the pipeline to allow any parameter in a template?

265 views
Skip to first unread message

adrian....@gmail.com

unread,
Dec 9, 2017, 3:12:35 PM12/9/17
to ISO C++ Standard - Future Proposals
The problem with templates is that you must specify a particular item you want as a parameter, such as a `typename`, a `template` or a `value`.  However, you can't say, specialize the template based on if the next parameter is any of those three.

I propose that there be a way to specialize based on these parameters like in the following example:
   
    template <...Xs>
   
struct X;

   
template <template <typename...> class TT>
   
struct X<TT> {};

   
template <typename T>
   
struct X<T> {};

   
template <typename T, T I>
   
struct X<I> {};

This would represent a template that takes a parameter pack of unspecified parameters, and is only accessible though specialization.

This allows the ability to have more control over template specialization while adding flexibility by allowing any parameter list. This on turn would allowing the creation of clearer and cleaner iinterfaces.

adrian....@gmail.com

unread,
Dec 9, 2017, 3:21:07 PM12/9/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
This would abide by current parameter pack expansion rules.

Adrian Hawryluk

unread,
Dec 9, 2017, 5:19:54 PM12/9/17
to ISO C++ Standard - Future Proposals
Apologies for the weird font size. Not sure why it's mega huge. I'll repost in a smaller fontwhen I get the chance.

adrian....@gmail.com

unread,
Dec 9, 2017, 7:30:55 PM12/9/17
to ISO C++ Standard - Future Proposals
Sorry about the weird font size of message at the beginning of the thread.  I had written it on my phone.  The following is an up to date copy of what I propose with significant edits:

The problem with templates is that you must specify a particular TPTs (template parameter types) you want as a parameter, such as a typename, a template or a value. However, you can't say, specialize the template based on if the next parameter is any of those three.


I propose that there be a way to specialize based on these parameters like in the following example:
    template <...Xs>
   
struct X;

   
template <template <typename...> class TT>
   
struct X<TT> {};

   
template <typename T>
   
struct X<T> {};

   
template <typename T, T I>
   
struct X<I> {};


   
// Or the last one could be stated as this, now
   
// that auto can be used in templates parameters:
   
template <auto I>
   
struct X<I> {};

The previous example is a simple representation of a template that takes a parameter pack of unspecified TPTs, and is only accessible though specialization, just like how all parameter packs are.  More complex usage is would be available as the untyped template parameter pack is available to be used like any parameter pack.  Such a UTPP would not be valid in all contexts of course, but that would go the same for typed template parameter packs, and the same rules would apply.

Having this would allow unconstrained, but type safe, traversal of any list, regardless of what the template parameter list is composed of, and allow the making of generic transforms.

bastie...@gmail.com

unread,
Dec 9, 2017, 11:37:54 PM12/9/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
No official proposal yet but I already started a thread about it here: https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/sZZ-Weg-kUA
Also your syntax doesn't allow for non-variadic generic template parameter.



adrian....@gmail.com

unread,
Dec 10, 2017, 12:33:37 AM12/10/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
No official proposal yet but I already started a thread about it here: https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/sZZ-Weg-kUA

Good to know.
 
Also your syntax doesn't allow for non-variadic generic template parameter.

The syntax I proposed was to be compatible with the current syntax.  I had considered using auto, but unfortunately, that has already been taken. Access to the any TPT would require specialization so that it would be able to be determined, and is why I chose the variadic template route as they already need to be specialized. 

adrian....@gmail.com

unread,
Dec 10, 2017, 10:06:57 AM12/10/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
A further alternative would be to have a placeholder and specialize on that:

    // Can't define a template with a placeholder TPT
   
template <placeholder>

   
struct X;

   
template <template <typename...> class TT>
   
struct X<TT> {};

   
template <typename T>
   
struct X<T> {};

   
template <typename T, T I>
   
struct X<I> {};


   
template <auto I>
   
struct X<I> {};

That would be useful to make it clear that a particular number of parameters is required on the top level.  Note that this is syntactic sugar, and is not really needed to make UTPTs work, but does make it easier to code and perhaps read.  I used a possible contextual keyword placeholder, but it is possible that just a blank TPT could also be used instead.  The only possible issue with that is it might be missed upon first reading of the code by a human, and maybe misconstrued as a template specialization.  Example:

    // Not a template specialization but a template with a single UTPT
   
template <>
   
struct X0;

   
// A template with two consecutive UTPT
   
template <,>
   
struct X1;

   
// A template with constant, a UTPT, and a type
   
template <auto I, , typename T>
   
struct X2;

Requiring the use of a contextual keyword would make it clearer of meaning:
    // Not a template specialization but a template with a single UTPT
   
template <placeholder>
   
struct X0;

   
// A template with two consecutive UTPT
   
template <placeholderplaceholder>
    struct X1;

   
// A template with constant, a UTPT, and a type
   
template <auto I, placeholder, typename T>
    struct X2;

Although, if it is made optional/not needed, one could use a comment instead for readability:
    // Not a template specialization but a template with a single UTPT
    
template </*placeholder*/>
   
struct X0;

    
// A template with two consecutive UTPT
    
template </*placeholder*/, /*placeholder*/>
    
struct X1;

    
// A template with constant, a UTPT, and a type
    
template <auto I, /*placeholder*/, typename T>
    
struct X2;

Currently, all contexts that I've stated are currently illegal, including the UTPT parameter pack, so would not impact current code in the wild.

adrian....@gmail.com

unread,
Dec 10, 2017, 10:41:11 AM12/10/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
    // Can't define a template with a placeholder TPT
   
template <placeholder>
   
struct X;
Note that I stated that you can't define a template with a UTPT.  I have reconsidered my stance on that as it might be useful to do so, so long as the UTPT is not needed in that context.

One further note is that UTPTs are unnamed, the only way to access that parameter is through specialization, at which point it becomes a real TPT, which if named, can be referenced.

adrian....@gmail.com

unread,
Dec 10, 2017, 10:49:36 AM12/10/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
One further note is that UTPTs are unnamed, the only way to access that parameter is through specialization, at which point it becomes a real TPT, which if named, can be referenced.

I've reconsidered this.  Instead of having a contextual keyword, we can use any non-keyword or blank if the parameter is not referenced.  If a single non-keyword is used, then this becomes its name, and is how you can reference a UTPT.  This is important if that parameter is to be handed off to another template.

bastie...@gmail.com

unread,
Dec 10, 2017, 11:20:01 AM12/10/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com


On Sunday, December 10, 2017 at 4:49:36 PM UTC+1, adrian....@gmail.com wrote:
One further note is that UTPTs are unnamed, the only way to access that parameter is through specialization, at which point it becomes a real TPT, which if named, can be referenced.

I've reconsidered this.  Instead of having a contextual keyword, we can use any non-keyword or blank if the parameter is not referenced.  If a single non-keyword is used, then this becomes its name, and is how you can reference a UTPT.  This is important if that parameter is to be handed off to another template.

Adding a new keyword to the language is a pain. This is not big enough to grant such a pain.
As for the empty solution is not a great solution because the intent is absolutely unclear, it's not easy to read and is really not C++-like.

Also you have decided without justification that such a placeholder can't be used.
I don't see why as a general-purpose template parameter could be quite useful.
It could be used to implement, for instance, named tuples for instance:

template<placeholder... X>
requires
(sizeof...(X) % 2 == 0) && (even_are_types_and_odd_string_literals<X...>())
struct named_tuple : even_into_tuple_t<X...>
{
     
template<auto& literal>
     
decltype(auto) get() noexcept { static_assert(literal_exists<literal>()); ... }
};

named_tuple
<std::string, "name", int, "age"> void get_student();
auto x = get_student().get<"name">();

And coupled with the meta_class proposal could allow to create real members using the non-type argument as name.

adrian....@gmail.com

unread,
Dec 10, 2017, 12:21:07 PM12/10/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Just a recap on how this would work:

A UTPT (undefined template parameter type) could be inserted into the language without breakage of current code in the wild by using currently illegal contexts, but is conceptually similar to how the current templating system works, so should be easy to grasp to those who know it.

To define a UTPT, you specify a non-keyword identifier into the template parameter list. This becomes the name of the UTPT. If the UTPT is not to be referenced, then that parameter can be left blank. A UTPT parameter pack can also be made by not stating the TPT (template parameter type) and just specify ... (ellipsis) followed by an optional non-keyword identifier.

A UTPT can only be passed to another template or specialized on, as its actual meaning is not understood at that context level. Once passed to another template, or is specialized on to become a DTPT (defined template parameter type) can it be actually be used.

As an example of how it could be used, I'll specify a tbinid class, which I made, used to bind template parameters:
template <template <typename...> class OP, typename PARAMS, typename...Ts>
struct tbind_impl;

template <template <typename...> class OP, typename...Ss>
struct tbind_impl<OP, std::tuple<Ss...>>
{
   
template<typename...Us>
   
using ttype = OP<Ss...>;
};

template <template <typename...> class OP, typename T, typename...Ts, typename...Ss>
struct tbind_impl<OP, std::tuple<Ss...>, T, Ts...>
{
   
template<typename...Us>
   
using ttype = typename tbind_impl<
          OP
       
, std::tuple<Ss..., T>
       
, Ts...
   
>::template ttype<Us...>;
};

template <template <typename...> class OP, size_t I, typename...Ts, typename...Ss>
struct tbind_impl<OP, std::tuple<Ss...>, std::integral_constant<size_t, I>, Ts...>
{
   
template<typename...Us>
   
using ttype = typename tbind_impl<
          OP
       
, typename std::tuple<
             
Ss...
           
, typename std::tuple_element<
                  I
               
, std::tuple<Us...>
             
>::type
         
>
       
, Ts...
   
>::template ttype<Us...>;

using t0 = std::integral_constant<size_t, 0>;
using t1 = std::integral_constant<size_t, 1>;
using t2 = std::integral_constant<size_t, 2>;
// ... other placeholders

template <template <typename...> class OP, typename...Ts>
struct tbind : tbind_impl<OP, std::tuple<>, Ts...>
{};

That is the original, and will bind only types to a template that only has types as its parameters. Now if UTPTs were allowed, we could do something like this:
template <...>
struct UTPT_list {};

template <size_t I, size_t N, ...Ts>
UTPT_element_impl
;

template <size_t I, size_t N, T, ...Ts>
UTPT_element_impl
<I, N, Ts...>
 
: UTPT_element_impl<I+1, N, Ts...>
{};

template <size_t N, auto V, ...Ts>
UTPT_element_impl
{
   
static constexpr auto item = V;
};

template <size_t N, typename T, ...Ts>
UTPT_element_impl
{
   
using item = T;
};

template <size_t N, template<...> TT, ...Ts>
UTPT_element_impl
{
   
template<...Us>
   
using item = T<Us...>;
};

template <size_t N, ...Ts>
UTPT_element
: UTPT_element_impl<0, N, Ts...> {};

template <template <...> class OP, typename PARAMS, ...Ts>
struct tbind_impl;

template <template <...> class OP, ...Ss>
struct tbind_impl<OP, UTPT_list<Ss...>>
{
   
template<...Us>
   
using ttype = OP<Ss...>;
};

template <template <...> class OP, T, ...Ts, ...Ss>
struct tbind_impl<OP, UTPT_list<Ss...>, T, Ts...>
{
   
template<...Us>
   
using ttype = typename tbind_impl<
          OP
       
, UTPT_list<Ss..., T>
       
, Ts...
   
>::template ttype<Us...>;
};

template <template <...> class OP, size_t I, ...Ts, ...Ss>
struct tbind_impl<OP, UTPT_list<Ss...>, std::integral_constant<size_t, I>, Ts...>
{
   
template<...Us>
   
using ttype = typename tbind_impl<
          OP
       
, typename UTPT_list<
             
Ss...
           
, UTPT_element<I, Us...>::item
         
>
       
, Ts...
   
>::template ttype<Us...>;

using t0 = std::integral_constant<size_t, 0>;
using t1 = std::integral_constant<size_t, 1>;
using t2 = std::integral_constant<size_t, 2>;
// ... other placeholders

template <template <...> class OP, ...Ts>
struct tbind : tbind_impl<OP, UTPT_list<>, Ts...>
{};

Which would allow binding of any template parameter no matter if a template parameter list consists of mixed TPTs.

Current usage would be:
// limited to templates that consist of only types
bool result = tbind<is_convertible, t1, long>::ttype<int>::value
// result == true

Where as it could be extended to something like this:
// these would result in a double type
tbind
<UTPT_element, 2, t0, t1, t2>::ttype<int, float, double>>::item x = 1.3;
tbind
<UTPT_element, t0, t1, t2, double>::ttype<2, int, float>>::item x = 1.3;

I hope this makes my intentions clear.

adrian....@gmail.com

unread,
Dec 10, 2017, 12:25:46 PM12/10/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com


On Sunday, December 10, 2017 at 11:20:01 AM UTC-5, bastie...@gmail.com wrote:


On Sunday, December 10, 2017 at 4:49:36 PM UTC+1, adrian....@gmail.com wrote:
One further note is that UTPTs are unnamed, the only way to access that parameter is through specialization, at which point it becomes a real TPT, which if named, can be referenced.

I've reconsidered this.  Instead of having a contextual keyword, we can use any non-keyword or blank if the parameter is not referenced.  If a single non-keyword is used, then this becomes its name, and is how you can reference a UTPT.  This is important if that parameter is to be handed off to another template.

Adding a new keyword to the language is a pain. This is not big enough to grant such a pain.
As for the empty solution is not a great solution because the intent is absolutely unclear, it's not easy to read and is really not C++-like.

Please see my example and tell me if that is unclear.
 
 Also you have decided without justification that such a placeholder can't be used.
I don't see why as a general-purpose template parameter could be quite useful.
It could be used to implement, for instance, named tuples for instance:

template<placeholder... X>
requires
(sizeof...(X) % 2 == 0) && (even_are_types_and_odd_string_literals<X...>())
struct named_tuple : even_into_tuple_t<X...>
{
     
template<auto& literal>
     
decltype(auto) get() noexcept { static_assert(literal_exists<literal>()); ... }
};

named_tuple
<std::string, "name", int, "age"> void get_student();
auto x = get_student().get<"name">();
And coupled with the meta_class proposal could allow to create real members using the non-type argument as name.

You're right, that wasn't my intention.  Of course you could use the UTPT identifier where the TPT is not needed.
 

adrian....@gmail.com

unread,
Dec 10, 2017, 12:29:34 PM12/10/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
This was an error:

template <size_t N, template<...> TT, ...Ts>
UTPT_element_impl
{
   
template<...Us>
   
using item = T<Us...>;
};

Should be:
template <size_t N, template<...> class TT, ...Ts>
UTPT_element_impl
{
   
template<...Us>
   
using item = TT<Us...>;
};


adrian....@gmail.com

unread,
Dec 10, 2017, 12:36:33 PM12/10/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Another error:

Was:
Current usage would be:
// limited to templates that consist of only types
bool result = tbind<is_convertible, t1, long>::ttype<int>::value
// result == true


Should be:
Current usage would be:
// limited to templates that consist of only types
bool result = tbind<is_convertible, t0, long>::ttype<int>::value
// result == true

 

adrian....@gmail.com

unread,
Dec 10, 2017, 2:21:15 PM12/10/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Amending this line: 
A UTPT can only be passed to another template or specialized on, as its actual meaning is not understood at that context level. Once passed to another template, or is specialized on to become a DTPT (defined template parameter type) can it be actually be used.

To this:
A UTPT can be used when passing to another template, used in specialized, or other contexts where the TPT is not needed such as with size...(), as its actual TPT is not understood at that context level. Once passed to another template, or is specialized on to become a DTPT (defined template parameter type) can it be actually be used. 

adrian....@gmail.com

unread,
Dec 13, 2017, 12:08:17 AM12/13/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
On Sunday, December 10, 2017 at 11:20:01 AM UTC-5, bastie...@gmail.com wrote:
Adding a new keyword to the language is a pain. This is not big enough to grant such a pain.
It is the reason why I didn't suggest one.

As for the empty solution is not a great solution because the intent is absolutely unclear, it's not easy to read and is really not C++-like.
As I said before, please see my example before jumping to the conclusion that the intent is absolutely unclear.  I feel quite the opposite.  If you name what you are asking for, then you get what you asked for.  If you don't ask for something specifically, then you get what you get.
 

adrian....@gmail.com

unread,
Dec 13, 2017, 12:40:43 AM12/13/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Suggested Proposal for Allowing Templates Take Unspecified Template Parameter Types

A UTPT (unspecified template parameter type) could be inserted into the language without breakage of current code in the wild by using currently illegal contexts, but is conceptually similar to how the current templating system works, so should be easy to grasp to those who know it. 


To define a UTPT, you specify a non-keyword identifier into the template parameter list. This becomes the name of the UTPT. If the UTPT is not to be referenced, then that parameter can be left blank. A UTPT parameter pack can also be made by not stating the TPT (template parameter type) and just specify ... (ellipsis) followed by an optional non-keyword identifier.

A UTPT can be used when passing to another template, used in specialized, or other contexts where the TPT is not needed such as with size...(). Once passed to another template, or is specialized on to become a DTPT (defined template parameter type) can it be used in the way that it is currently done in C++. 

As an example of how it could be used, I'll specify a tbind class, which I made, used to bind template parameters:
That is the original, and will only bind to TPTs of a typename. Now if UTPTs were allowed, using the specification I suggested, we could do something like this:
// A replacement for std::tuple for UTPTs
template <...>
struct UTPT_list {};

// A replacement for std::tuple_element for UTPTs

template <size_t I, size_t N, ...Ts>
UTPT_element_impl
;

template <size_t I, size_t N, T, ...Ts>
UTPT_element_impl
<I, N, Ts...>
 
: UTPT_element_impl<I+1, N, Ts...>
{};

template <size_t N, auto V, ...Ts>
UTPT_element_impl
{
   
static constexpr auto item = V;
};

template <size_t N, typename T, ...Ts>
UTPT_element_impl
{
   
using item = T;
};

template <size_t N, template<...> class TT, ...Ts>
UTPT_element_impl
{
   
template<...Us>
   
using item = TT<Us...>;
};


Current usage would be:
// limited to templates that consist of only types
bool result = tbind<is_convertible, t0, long>::ttype<int>::value
// result == true

adrian....@gmail.com

unread,
Dec 13, 2017, 1:03:20 AM12/13/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Just to note, it is trivial to determine what type the TPT is using specialization:
// Note that the name UTPT here is optional, just like it would be for a regular template to be specialized
template <UTPT>
struct is_template : std::false_type {};

// This is a specialization that can take a template that can take any number of UTPT.
template <template <...> TT>
struct is_template<TT> : std::true_type {};

I'll leave the rest of the is_* TPT checkers up to the reader.

inkwizyt...@gmail.com

unread,
Dec 13, 2017, 3:06:54 PM12/13/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Some time ago I participate in discussion of similar feature. One difference was that was using `using` keyword to introduce unknown type of template parameters. I think use in this context will be consisting with rest of language because you can `using` not only types but function too.

adrian....@gmail.com

unread,
Dec 13, 2017, 3:45:07 PM12/13/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Some time ago I participate in discussion of similar feature. One difference was that was using `using` keyword to introduce unknown type of template parameters. I think use in this context will be consisting with rest of language because you can `using` not only types but function too.

Well, I think using is better keyword to use than the bare template keyword IMHO.   When I see template, I just expect to see a template there, not any TPT.  Other alternatives I considered were auto, as it would automatically match any TPT, but that is currently in use now, and * (asterix), which is like a glob that matches everything.  The use of no keyword was a fairly obvious mnemonic, I didn't specify what TPT, so allow any TPT.

Quite honestly, I don't really mind any of these alternatives, but I think that we should not be limited like we are now.  This feature is a long time coming and should be added to the language.

What other differences were there in the other discussion you had?  What reason was given to blockade this type of feature?

Mingxin Wang

unread,
Dec 13, 2017, 10:09:41 PM12/13/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
I think "allowing any parameter in a template" is a common demand, especially in compile-time programming.

With the standard we have now, one is always required to specify the types of the parameters declared in a template. In order to define the semantics of the template explicitly, the class template `std::integral_constant` was introduced, so that users are able to pass any integral constants with the template. However, I think `integral_constant` is inappropriately named, and there seem to be little necessity in defining any member types or constants in it, because these metadata is already passed by templates.

In order to standardize the expressions to pass various sort of metadata to templates, the class templates `in_place_arg_t` and `in_place_resource_t` were proposed in one of my earlier posts (https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/Gb3CFKiGLfo) and in my recent proposal p0801 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0801r0.pdf).

What do you think of my solution? I am looking forward to your comments and suggestions.

Mingxin Wang

bastie...@gmail.com

unread,
Dec 14, 2017, 3:31:03 AM12/14/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
I'm sorry but more of the same is not going to help here.
A library solution doesn't help.
std::integral_constant & affiliated solutions are generally extremely clunky and require the user of to work for the solution to be functional.

I actually disagree on your statement that's it's not possible.
The only issue with it is C++ parsing and there is a simple solution.
I proposed it in an earlier thread, that said "universal template parameter" ought to behave as dependent members:
-implicitly value.
-requires prefix "typename" if used, or tried to be used, as type.
-requires prefix "template" if is a template template parameter.

With the difference that when giving such an argument to a template instantiation list the value/type must be substituted for the parsed one.

Ex:
template<template T>
constexpr auto  func()
{
   
if constexpr (requires() { T; })
       
return T;
   
else if constexpr (requires() { typename T; })
       
return typename T{};
   
else
       
return template T<>{};
}

template<template T>
constexpr void x()
{
   func
<T>(); //is pre-parsed as a dependent template argument. T is then substituted on instantiation by its actual value.
}

int main(){
   x
<42>(); //ok
   x
<int>(); //ok
}

Having seen from close GCC implementation I believe it's technically doable.

On the syntax front I disagree on the use of "using" and the justification behind it.
"using" has one meaning : name substitution. With namespaces, classes and functions. NOT values.
"template" is actually more appropriate.
Template only means canvas, to be substituted by.
You can template any kind of definition.
Using "template" as a universal template argument seems more intuitive than "using".
"template" in a template parameter list would simply mean:
a parameter-less template, something to be resolved as template doesn't infer what is actually templated.

Mingxin Wang

unread,
Dec 14, 2017, 5:24:41 AM12/14/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
On Thursday, December 14, 2017 at 4:31:03 PM UTC+8, bastie...@gmail.com wrote:
I'm sorry but more of the same is not going to help here.
A library solution doesn't help.
std::integral_constant & affiliated solutions are generally extremely clunky and require the user of to work for the solution to be functional.

If it is required to specify various types of metadata to a class template, there seems to be no necessity to use other utilities, e.g.:

template <class ENUM_T, ENUM_T E>
class foo {
  // ...
};

I actually disagree on your statement that's it's not possible.

I did not seem to say something "not possible" in my statement. What do you mean by the "it"?
 
The only issue with it is C++ parsing and there is a simple solution.
I proposed it in an earlier thread, that said "universal template parameter" ought to behave as dependent members:
-implicitly value.
-requires prefix "typename" if used, or tried to be used, as type.
-requires prefix "template" if is a template template parameter.

That will be a new language feature. However, the motivation of it seems to be insufficient, because:
1. The idea will carry unnecessary ambiguation to the semantics of the template, and further reduce the maintainability of the product.
2. I could not find a case that your idea could give full play to the advantages.
 
With the difference that when giving such an argument to a template instantiation list the value/type must be substituted for the parsed one.

Ex:
template<template T>
constexpr auto  func()
{
   
if constexpr (requires() { T; })
       
return T;
   
else if constexpr (requires() { typename T; })
       
return typename T{};
   
else
       
return template T<>{};
}

template<template T>
constexpr void x()
{
   func
<T>(); //is pre-parsed as a dependent template argument. T is then substituted on instantiation by its actual value.
}

int main(){
   x
<42>(); //ok
   x
<int>(); //ok
}

Having seen from close GCC implementation I believe it's technically doable.

I think this case properly illustrates the syntax you designed, but could not prove the reasonableness of your idea, because there seems to be little motivation for a user to design the function template `func` defined above, and thus this case seems to be meaningless.
 
On the syntax front I disagree on the use of "using" and the justification behind it.
"using" has one meaning : name substitution. With namespaces, classes and functions. NOT values.
"template" is actually more appropriate.
Template only means canvas, to be substituted by.
You can template any kind of definition.
Using "template" as a universal template argument seems more intuitive than "using".
"template" in a template parameter list would simply mean:
a parameter-less template, something to be resolved as template doesn't infer what is actually templated.

From my point of view, the template is a container of metadata, and "type" is a the basic type of metadata because any "value metadata" has a type, and that "type" is also a part of metadata. Thus, I think, the type of the "value metadata" should not be ignored in a template.

bastie...@gmail.com

unread,
Dec 14, 2017, 9:25:24 AM12/14/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com


On Thursday, December 14, 2017 at 11:24:41 AM UTC+1, Mingxin Wang wrote:
On Thursday, December 14, 2017 at 4:31:03 PM UTC+8, bastie...@gmail.com wrote:
I'm sorry but more of the same is not going to help here.
A library solution doesn't help.
std::integral_constant & affiliated solutions are generally extremely clunky and require the user of to work for the solution to be functional.

If it is required to specify various types of metadata to a class template, there seems to be no necessity to use other utilities, e.g.:

template <class ENUM_T, ENUM_T E>
class foo {
  // ...
}; 

My point was that std::integral_constant is a hack and we don't need more hack on the user-side.


I actually disagree on your statement that's it's not possible.

I did not seem to say something "not possible" in my statement. What do you mean by the "it"?

"With the standard we have now, one is always required to specify the types of the parameters declared in a template."
 
 
The only issue with it is C++ parsing and there is a simple solution.
I proposed it in an earlier thread, that said "universal template parameter" ought to behave as dependent members:
-implicitly value.
-requires prefix "typename" if used, or tried to be used, as type.
-requires prefix "template" if is a template template parameter.

That will be a new language feature. However, the motivation of it seems to be insufficient, because:
1. The idea will carry unnecessary ambiguation to the semantics of the template, and further reduce the maintainability of the product.
I don't see where you see ambiguation.
"template" in a template argument list is not possible now and would only impact the parsing of template template parameters.
As for reducing  the maintainability that's false and unjustified.

2. I could not find a case that your idea could give full play to the advantages.
 I can give you one that's would be simple to use and useful : named_tuple.

named_tuple<int, "age", string, "name"> x;
x
.get<"name">() = get_user_name();
static_assert(std::is_same_v<std::string &, decltype(std::get<1>())>);

 
With the difference that when giving such an argument to a template instantiation list the value/type must be substituted for the parsed one.

Ex:
template<template T>
constexpr auto  func()
{
   
if constexpr (requires() { T; })
       
return T;
   
else if constexpr (requires() { typename T; })
       
return typename T{};
   
else
       
return template T<>{};
}

template<template T>
constexpr void x()
{
   func
<T>(); //is pre-parsed as a dependent template argument. T is then substituted on instantiation by its actual value.
}

int main(){
   x
<42>(); //ok
   x
<int>(); //ok
}

Having seen from close GCC implementation I believe it's technically doable.

I think this case properly illustrates the syntax you designed, but could not prove the reasonableness of your idea, because there seems to be little motivation for a user to design the function template `func` defined above, and thus this case seems to be meaningless.
Are you arguing that a demonstration is not an use-case? That's weak.
On the reasonableness of the idea, you, yourself, said that it was a popular request and would be useful for metaprogramming purpose.
 
On the syntax front I disagree on the use of "using" and the justification behind it.
"using" has one meaning : name substitution. With namespaces, classes and functions. NOT values.
"template" is actually more appropriate.
Template only means canvas, to be substituted by.
You can template any kind of definition.
Using "template" as a universal template argument seems more intuitive than "using".
"template" in a template parameter list would simply mean:
a parameter-less template, something to be resolved as template doesn't infer what is actually templated.

From my point of view, the template is a container of metadata, and "type" is a the basic type of metadata because any "value metadata" has a type, and that "type" is also a part of metadata. Thus, I think, the type of the "value metadata" should not be ignored in a template.
No. Metadata is data about data, it's a state that describe a state.
A template is declarative. It's a parameterized definition nothing else.
Regardless because we are talking about the keyword template inside a template parameter list.
I chose template because it doesn't require a new keyword and a template can be used to parameterize any type of definition (type, variable, function, using, etc...).
Here the logical reasoning as to why template.

If we take a template template parameter : template<class> class T.
template<class> class T means a type named T parameterized over a type.
template class T would be the same thing as class T, a type named T parameterized over nothing, pointless so not implemented.
template T is something parameterized over nothing, in other words: something.

It's quite similar to the transformation that occurred with auto from C to C++.
auto int x, in C++98 && C auto was useless here as it was the default storage of a local variable.
auto x, since C++11 this means variable of automatic type and now auto int x is no longer legal.

Nicol Bolas

unread,
Dec 14, 2017, 11:06:57 AM12/14/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
On Thursday, December 14, 2017 at 9:25:24 AM UTC-5, bastie...@gmail.com wrote:
On Thursday, December 14, 2017 at 11:24:41 AM UTC+1, Mingxin Wang wrote:
On Thursday, December 14, 2017 at 4:31:03 PM UTC+8, bastie...@gmail.com wrote
2. I could not find a case that your idea could give full play to the advantages.
 I can give you one that's would be simple to use and useful : named_tuple.

named_tuple<int, "age", string, "name"> x;
x
.get<"name">() = get_user_name();
static_assert(std::is_same_v<std::string &, decltype(std::get<1>())>);


Which can be accomplished adequately enough in other ways (assuming we allow strings in template parameters):

named_tuple<tag<"age", int>, tag<"name", string>>;

Indeed, I think this would be a much better solution. First, it allows you to have named_tuples with unnamed elements (`named_tuple<int, tag<"name", string>>`). Second, I think it makes it easier on the implementation side. For example, if you want to write a metafunction that takes a `named_tuple<...>` and generates a list of its types, you can do this:

template<typename T>
struct get_type_from_tag
{
 
using type = T;
};

template<const char *Str, typename T>
struct get_type_from_tag<tag<Str, T>
{
 
using type = T;
};

template<T>
using get_type_from_tag_t = typename get_type_from_tag<T>::type;

template<typename Tpl>
struct types_from_tuple {};

template<typename ...Ts>
struct types_from_tuple<named_tuple<Ts...>>
{
 
using type = type_list<get_type_from_tag_t<Ts>...>;
};

The metafunction for your code's equivalent would not be able to use expansion like that. Since every pair of `T` in the argument list contains the actual type, you would need to use recursion to extract the list of `T`s. Not the hardest thing in the world, but hardly as straightforward as this.

I think this case properly illustrates the syntax you designed, but could not prove the reasonableness of your idea, because there seems to be little motivation for a user to design the function template `func` defined above, and thus this case seems to be meaningless.
Are you arguing that a demonstration is not an use-case? That's weak.
 
What is so "weak" about it? An artificial example that doesn't have real-world utility is not an effective motivation for a feature. I admit that I'm not a deep metaprogramming expert, so it is entirely possible I'm missing something here. But thus far, I have not seen a genuinely compelling use case that cannot adequately be solved with some other mechanism.

bastie...@gmail.com

unread,
Dec 14, 2017, 11:53:55 AM12/14/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
On Thursday, December 14, 2017 at 5:06:57 PM UTC+1, Nicol Bolas wrote:
On Thursday, December 14, 2017 at 9:25:24 AM UTC-5, bastie...@gmail.com wrote:
On Thursday, December 14, 2017 at 11:24:41 AM UTC+1, Mingxin Wang wrote:
On Thursday, December 14, 2017 at 4:31:03 PM UTC+8, bastie...@gmail.com wrote
2. I could not find a case that your idea could give full play to the advantages.
 I can give you one that's would be simple to use and useful : named_tuple.

named_tuple<int, "age", string, "name"> x;
x
.get<"name">() = get_user_name();
static_assert(std::is_same_v<std::string &, decltype(std::get<1>())>);


Which can be accomplished adequately enough in other ways (assuming we allow strings in template parameters): 
strings as template parameters was adopted by the evolution working group during the meeting of November : https://botondballo.wordpress.com/2017/11/20/trip-report-c-standards-meeting-in-albuquerque-november-2017/ 

named_tuple<tag<"age", int>, tag<"name", string>>;
 
Indeed, I think this would be a much better solution. First, it allows you to have named_tuples with unnamed elements (`named_tuple<int, tag<"name", string>>`). Second, I think it makes it easier on the implementation side. For example, if you want to write a metafunction that takes a `named_tuple<...>` and generates a list of its types, you can do this:

template<typename T>
struct get_type_from_tag
{
 
using type = T;
};

template<const char *Str, typename T>
struct get_type_from_tag<tag<Str, T>
{
 
using type = T;
};

template<T>
using get_type_from_tag_t = typename get_type_from_tag<T>::type;

template<typename Tpl>
struct types_from_tuple {};

template<typename ...Ts>
struct types_from_tuple<named_tuple<Ts...>>
{
 
using type = type_list<get_type_from_tag_t<Ts>...>;
};

The metafunction for your code's equivalent would not be able to use expansion like that. Since every pair of `T` in the argument list contains the actual type, you would need to use recursion to extract the list of `T`s. Not the hardest thing in the world, but hardly as straightforward as this.

I agree that it can be expressed through type tagging. That being said do you think that such a solution could ever be part of std?
This is an odd pattern that requires implementation knowledge on the part of the user.
On the implementation side I've worked on a non-recursive implementation that would rely on lambdas in unevaluated context (also opted in C++20) and that I believe could also allow optional names.
That being said it is more difficult to write but library features are usually more difficult to write the more they wish to be easy to use.


I think this case properly illustrates the syntax you designed, but could not prove the reasonableness of your idea, because there seems to be little motivation for a user to design the function template `func` defined above, and thus this case seems to be meaningless.
Are you arguing that a demonstration is not an use-case? That's weak.
 
What is so "weak" about it? An artificial example that doesn't have real-world utility is not an effective motivation for a feature. I admit that I'm not a deep metaprogramming expert, so it is entirely possible I'm missing something here. But thus far, I have not seen a genuinely compelling use case that cannot adequately be solved with some other mechanism.
What is weak is to argue that an illustration used to showcase how something would work is a bad use case. It's not a use case and wasn't written to be one.

Nicol Bolas

unread,
Dec 14, 2017, 12:30:43 PM12/14/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
... why not?

Whether you use a tag type or your suggestion, it would be a very breaking change to allow `std::tuple` itself to gain this feature. After all, people already have a lot of code that expects `tuple` to take only typenames, and that those typenames directly map to the types the `tuple` stores.

So however it happens, it must be a new type. And there's no reason why the `tag`ed version couldn't be standardized.

This is an odd pattern that requires implementation knowledge on the part of the user.

No more odd than the idea that you pass a sequence of string and type pairs. Certainly, no other type accepts such a thing at present.

By contrast, while the standard library doesn't use tagged template parameters, there are several C++ libraries that do. So at least some programmers are familiar with the concept.

On the implementation side I've worked on a non-recursive implementation that would rely on lambdas in unevaluated context (also opted in C++20) and that I believe could also allow optional names.
That being said it is more difficult to write but library features are usually more difficult to write the more they wish to be easy to use.

I thought the whole point of this feature was to make template programming easier, not harder.

Message has been deleted

adrian....@gmail.com

unread,
Dec 16, 2017, 10:01:22 AM12/16/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Although your proposal is interesting, I don't see how it relates to this thread.

This thread isn't about how we can encapsulate an type (if that is what you are getting at, which doesn't seem to be the case as you can't encapsulate templates in that manner).  This is about being able to accept and manipulate any TPT, thus allowing more general transforms of any template.  My tbind example above is a real world example of this. 

Mingxin Wang

unread,
Dec 17, 2017, 4:12:54 AM12/17/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
On Saturday, December 16, 2017 at 11:01:22 PM UTC+8, adrian....@gmail.com wrote:

Although your proposal is interesting, I don't see how it relates to this thread.

This thread isn't about how we can encapsulate an type (if that is what you are getting at, which doesn't seem to be the case as you can't encapsulate templates in that manner).  This is about being able to accept and manipulate any TPT, thus allowing more general transforms of any template.  My tbind example above is a real world example of this. 

I am sorry that I did not get your idea at the beginning. If my understanding is correct this time, your intension is to popularize the term "overloading" to type templates.

I think it is worth trying. Overloading is a technique that allows one to name different "reusable functional units" having similar semantics with a same identifier. Popularizing this term to templates seems natural, and we already have partial support of it, e.g. `template <typename...>` and `template <typename T, T I>`.

However, some details might need to be taken into account before standardization.

1. Is the motivation strong enough to define a new language feature?

There is partial support of "template overloading" in the standard, and "overloading" is not inevitable. After all, any case that could be solved by overloading, could be easily handled with renaming.

2. If we have "template overloading", do we still need "template specialization"?

"template specialization" is a widely used technique, and it seems that "template overloading" has some overlap with "template specialization". If there is enough motivation to keep both features for type templates, is it necessary to let function templates support "template specialization"? Otherwise, do we still need "template specialization"?

Mingxin Wang

adrian....@gmail.com

unread,
Dec 17, 2017, 10:06:20 PM12/17/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com


On Sunday, December 17, 2017 at 4:12:54 AM UTC-5, Mingxin Wang wrote:
On Saturday, December 16, 2017 at 11:01:22 PM UTC+8, adrian....@gmail.com wrote:

Although your proposal is interesting, I don't see how it relates to this thread.

This thread isn't about how we can encapsulate an type (if that is what you are getting at, which doesn't seem to be the case as you can't encapsulate templates in that manner).  This is about being able to accept and manipulate any TPT, thus allowing more general transforms of any template.  My tbind example above is a real world example of this. 

I am sorry that I did not get your idea at the beginning. If my understanding is correct this time, your intension is to popularize the term "overloading" to type templates.

No, not overloading.  This is template specialization, with all the same rules that that entails.  It would be considered the least specialized when matching specializations.  Please see my example above for a more detailed use case.  However, you can see this work in the following minimal example:

// Template declaration
template <T>
struct X;


// Specialization 1
template <auto C>
struct X<C>
{
 
// C is a template constant
};


// Specialization 1a
template <typename T, T C>
struct X<C>
{
 
// C is a template constant (same as above)
 
// T is the type of the constant
 
// This specialization cannot exist in tandem with the one above
 
// (Specialization 1) as they are equivalent and would cause an ambiguity
 
// error.
};


// Specialization 2

template <typename T>
struct X<T>
{

 
// T is a typename
};


// Specialization 3
template <template <...> class TT>
struct X<TT>
{
 
// TT is a template that takes any number of UTPT.
};


// Specialization 3a
template <template <auto...> class TT>
struct X<TT>
{
 
// TT is a template that takes any number of constant TPTs.
};


// Specialization 3b

template <template <typename...> class TT>
struct X<TT>
{

 
// TT is a template that takes any number of typename TPTs.
};


// Specialization 3c
template <template <template <...> class...> class TT>
struct X<TT>
{
 
// TT is a template that takes any number of template TPTs that take any
 
// number of UTPTs.
};


// Specialization 3d
template <template <template <...> class, typename, int> class TT>
struct X<TT>
{
 
// TT is a template that takes a template that takes any number of UTPTs and
 
// a typename and an int constant.
};


The list can go on and on.
 
However, some details might need to be taken into account before standardization.

1. Is the motivation strong enough to define a new language feature?

There is partial support of "template overloading" in the standard, and "overloading" is not inevitable. After all, any case that could be solved by overloading, could be easily handled with renaming.

We are not defining a new feature  exactly, but extending an already existing one (template specialization) such that the template parameter type (TPT) can be unspecified. 

2. If we have "template overloading", do we still need "template specialization"?

"template specialization" is a widely used technique, and it seems that "template overloading" has some overlap with "template specialization". If there is enough motivation to keep both features for type templates, is it necessary to let function templates support "template specialization"? Otherwise, do we still need "template specialization"?

Again, this is template specialization not template overloading.  If we attempted to add template overloading (if I understand your concept of it), it would require a lot of vetting as it would be a large departure from what the language supports now.  What I am talking about is a tweak of the current system which is far less risky.


adrian....@gmail.com

unread,
Dec 18, 2017, 12:08:34 AM12/18/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Oh, and if we used the template keyword as was suggested by Nicol, it would be alternate would be 

// Template declaration
template <template T>

struct X;

// Specialization 1
template <auto C>
struct X<C>
{
 
// C is a template constant
};

// Specialization 1a
template <typename T, T C>
struct X<C>
{
 
// C is a template constant (same as above)
 
// T is the type of the constant
 
// This specialization cannot exist in tandem with the one above
 
// (Specialization 1) as they are equivalent and would cause an ambiguity
 
// error.
};

// Specialization 2
template <typename T>
struct X<T>
{
 
// T is a typename
};

// Specialization 3
template <template <template...> class TT>

struct X<TT>
{
 
// TT is a template that takes any number of UTPT.
};

// Specialization 3a
template <template <auto...> class TT>
struct X<TT>
{
 
// TT is a template that takes any number of constant TPTs.
};

// Specialization 3b
template <template <typename...> class TT>
struct X<TT>
{
 
// TT is a template that takes any number of typename TPTs.
};

// Specialization 3c
template <template <template <template...> class...> class TT>

struct X<TT>
{
 
// TT is a template that takes any number of template TPTs that take any
 
// number of UTPTs.
};

// Specialization 3d
template <template <template <template...> class, typename, int> class TT>

struct X<TT>
{
 
// TT is a template that takes a template that takes any number of UTPTs and
 
// a typename and an int constant.
};

However, I still don't like the use of the keyword template in this as I personally find it more confusing to the reader.  Using no keyword or perhaps another keyword would prolly be better.

Mingxin Wang

unread,
Dec 18, 2017, 1:10:53 AM12/18/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
It seems that you are proposing a core language feature that allows one to pass ANYTHING (types, type templates, constexpr values, etc.) on template instantiation.

I think the motivation of this idea is not strong enough to a certain extent, because:

1. Types, type templates and constexpr values usually have completely different semantics. Thus using this feature will inevitably carry ambiguation to the semantics of the templates. For example, if one is supposed to define some types like `X<int>` (type), `X<123>` (constexpr value) and `X<std::vector>` (type template), I do not agree that the three types shall have the same semantics, thus they shall have different names for their respective semantics, rather than sharing a same one.

2. Any case that could be solved by this feature, could also be easily handled with renaming.

3. Although you are "extending an already existing feature", it is still a core language feature that requires support from the compiler.

However, some details might need to be taken into account before standardization.

1. Is the motivation strong enough to define a new language feature?

There is partial support of "template overloading" in the standard, and "overloading" is not inevitable. After all, any case that could be solved by overloading, could be easily handled with renaming.

We are not defining a new feature  exactly, but extending an already existing one (template specialization) such that the template parameter type (TPT) can be unspecified. 

2. If we have "template overloading", do we still need "template specialization"?

"template specialization" is a widely used technique, and it seems that "template overloading" has some overlap with "template specialization". If there is enough motivation to keep both features for type templates, is it necessary to let function templates support "template specialization"? Otherwise, do we still need "template specialization"?

Again, this is template specialization not template overloading.  If we attempted to add template overloading (if I understand your concept of it), it would require a lot of vetting as it would be a large departure from what the language supports now.  What I am talking about is a tweak of the current system which is far less risky.

Actually, I think "template overloading" might be more acceptible than the feature you propose; at least, it does not break the existing rules in declaring a template, and does not require new keywords (or reuse some existing keywords) with new semantics.

Mingxin Wang

adrian....@gmail.com

unread,
Dec 18, 2017, 8:52:04 AM12/18/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Yes
 
I think the motivation of this idea is not strong enough to a certain extent, because:

1. Types, type templates and constexpr values usually have completely different semantics. Thus using this feature will inevitably carry ambiguation to the semantics of the templates. For example, if one is supposed to define some types like `X<int>` (type), `X<123>` (constexpr value) and `X<std::vector>` (type template), I do not agree that the three types shall have the same semantics, thus they shall have different names for their respective semantics, rather than sharing a same one.

How does it carry ambiguation to the semantics of templates?  Being able to transform any template list to another or into an object would benefit from this.  If you had ever had to wrap a constant in an integral_constant just so that it is a type that you can iterate over, then you should be able to see that that case can be helped with using this proposal.
 
2. Any case that could be solved by this feature, could also be easily handled with renaming.
 
Have you looked at the tbind example above?  This shows that this feature cannot be handled with renaming, easily or otherwise..
 
3. Although you are "extending an already existing feature", it is still a core language feature that requires support from the compiler. 

However, some details might need to be taken into account before standardization.

1. Is the motivation strong enough to define a new language feature?

There is partial support of "template overloading" in the standard, and "overloading" is not inevitable. After all, any case that could be solved by overloading, could be easily handled with renaming.

We are not defining a new feature  exactly, but extending an already existing one (template specialization) such that the template parameter type (TPT) can be unspecified. 

2. If we have "template overloading", do we still need "template specialization"?

"template specialization" is a widely used technique, and it seems that "template overloading" has some overlap with "template specialization". If there is enough motivation to keep both features for type templates, is it necessary to let function templates support "template specialization"? Otherwise, do we still need "template specialization"?

Again, this is template specialization not template overloading.  If we attempted to add template overloading (if I understand your concept of it), it would require a lot of vetting as it would be a large departure from what the language supports now.  What I am talking about is a tweak of the current system which is far less risky.

Actually, I think "template overloading" might be more acceptible than the feature you propose; at least, it does not break the existing rules in declaring a template, and does not require new keywords (or reuse some existing keywords) with new semantics.

Yes, it still does require compiler support. However, the rules for template specialization are well understood and an extension would be more trivial (not trivial, but more so) then attempting to add on a completely new feature of template overloading.  This would be an extension to the bottom of the template specialization rules as they stand now.  This feature would not break any existing rules and not break any existing code.

bastie...@gmail.com

unread,
Dec 19, 2017, 1:33:38 PM12/19/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Enter code here...
Actually I said it was useful and easier to use, not that it somehow made variadic templates easy to handle.
The point of this idea is to increase expressivity for the library writer and simplify its utilisation by the user.
As for the unevaluated lambdas, it is not required at all but they have the benefit to be inaccessible for the user (as opposed to tool classes/fn hidden in namespaces).

My issue with tagged types is that it's a fix not a solution.
It's a pattern where the user has to know a type and a tool type just to use it (two names required to express one idea).
I'm aware that it is used by a bunch of libraries and the reason why they do so is because there are no alternatives (or they are even worse for the user: decltype over overload function call, etc..).

Going back the the generic template parameter idea, generally speaking this idea has the same goals, consequences, etc..., as the "auto non-type parameter" proposal had.

On the named_tuple example, I believe that allowing a variable amount of strings after the type would make the tag implementation more difficult without really affecting the "template" one.
using note = named_tuple<int, "year", "month", "day", double, "grade", std::string, "subject">;
using note = named_tuple<tag<int,"year","month","day">, tag<double, "grade">, tag<std::string,"subject">>;

Nicol Bolas

unread,
Dec 19, 2017, 3:16:16 PM12/19/17
to ISO C++ Standard - Future Proposals, adrian....@gmail.com
Does C++ really need more ways to be hard to use?

The point of this idea is to increase expressivity for the library writer and simplify its utilisation by the user.
As for the unevaluated lambdas, it is not required at all but they have the benefit to be inaccessible for the user (as opposed to tool classes/fn hidden in namespaces).

My issue with tagged types is that it's a fix not a solution.
It's a pattern where the user has to know a type and a tool type just to use it (two names required to express one idea).

But it leads to better, more reasonable, and more easily understood code, for both the user and the library writer. If you see `tagged_tuple<tag<int, "name">>`, a user can make some guesses about what's going on. But if you see `named_tuple<int, "name">`, you're not sure what's going on. There is no obvious relationship between the type and the string.

Furthermore, I'm pretty sure the compile error given by `tagged_tuple<tag<"name", int>>` will be a lot easier to understand than the one by `named_tuple<"name", int>`.

I'm aware that it is used by a bunch of libraries and the reason why they do so is because there are no alternatives (or they are even worse for the user: decltype over overload function call, etc..).

Going back the the generic template parameter idea, generally speaking this idea has the same goals, consequences, etc..., as the "auto non-type parameter" proposal had.

On the named_tuple example, I believe that allowing a variable amount of strings after the type would make the tag implementation more difficult without really affecting the "template" one.

But that's only because the generic one is already such a nightmarish beast to implement that it can't really get worse.
Reply all
Reply to author
Forward
0 new messages