atomgalaxy / isocpp-universal-template-param

We propose a way to spell a universal template parameter kind. This would allow for a generic apply and other higher-order template metafunctions, and certain typetraits.
https://atomgalaxy.github.io/isocpp-universal-template-param/d1985r0.pdf
2 stars 2 forks source link

Interaction with P2601: Allow omitting <> for class templates w. default arguments. #52

Open BengtGustafsson opened 1 year ago

BengtGustafsson commented 1 year ago

There is an interaction between the proposals.


template<__any U> struct X {
    template U* v;    // If U is bound to a class template with all arguments defaulted this is ok and declares a pointer.
    template U<int> w;
};

template<typename T = int> class Y {
};

using Z = X<Y>;   // Y's kind is template, not class!

This seems ambiguous as the Y on the last line could either mean Y, and U being bound to a class template, or Y and U being bound to a class.

The problem is if we introduce template varaible template parameters. Then we get into another ambiguity with the declaration of v above. According to what has already been discussed in the proposal (or at least in another issue) this case would now require double disambiguation:


template<__any U> struct X {
    typename template U* v;    // If U is bound to a class template with all arguments defaulted this is ok and declares a pointer.
    template U<int> w;
};

template<typename T = int> class Y {
};

using Z = X<Y>;   // Y's kind is template, not class!

// ------------------- whereas ------------------------ //

int v;
template<__any U> struct X {
    template U* v;    // If U is bound to a variable template with all arguments defaulted this is ok and performs multiplication.
    template U<int> w;
};

template<typename T = int> int Y  = sizeof(T);

using Z = X<Y>;   // Y's kind is template, not value!

An observation here is that the issue of omitting <> according to P2601 is orthogonal to the issue of having to double-disambiguate UTPs supposed to be bound to class templates to avoid them being treated as variable templates. This seems to call for inclusion of variable template template parameters in the same proposal, as otherwise it would be odd to demand the apparently unnecessary double disambiguation.

But maybe there is another solution: Only require the typename disambiguation, and add a special rule that if a UTP has been disambiguated to type and a < follows immediately after the UTP's name then the UTP is actually disambiguated to class template and the part after < is treated as a template argument list. If the UTP is disambiguated using template it is instead treated as a variable template in that after the > of the following template argument list has been parsed the result is treated as a value, i.e. an instance of a variable template. A further rule is that if there is no < after the UTP name the UTP is assumed to be a type or a class template with all arguments defaulted if disambiguated by typename and a value or a variable template with all arguments defaulted if not. At parse time the kind is well known so further parsing should not be an issue.

NOTE: What could be an issue with P2601 itself is that for a variable template a < folliowng the name of a variable template with all template arguments defaulted is formally ambiguous between being the start of a template parameter list and a less than operator on the defaulted specialization of the variable template. It seems very logical that such a < is always treated as the start of a template argument list but it should be mentioned in P2601, and I don't know if it is.

template<auto V = char> int W  = V * sizeof(decltype(V);

W<3>;  // Expression yielding 12 or expression yielding 3 < 3 and then parse failure fail on ; as > lacks its second operand?