I think the following code is well-formed:
template< typename T >
using IsSigned = std::enable_if_t< std::is_signed_v< T > >;
template< typename T, IsSigned< T >... >
T myAbs( T val );
Others say that it is ill-formed, because §17.7 (8.3) of the C++17 standard:
Knowing which names are type names allows the syntax of every template to be checked. The program is ill-formed, no diagnostic required, if: (...) every valid specialization of a variadic template requires an empty template parameter pack, or (...)
In my opinion IsSigned< T >...
is a dependent template parameter, therefore it can not be checked against §17.7 (8.3) in template definition time. IsSigned< T >
could be for example void
for one subset of Ts, int
for another subset or substitution failure. For the void
subset it is true, that the empty template parameter pack would be the only valid specialization, but the int
subset could have many valid specializations. It depends on the actual T
argument.
It means that the compiler must check it after the template instantiation, because T is not known before. At that point the full argument list is known, there is zero variadic arguments. The standard says the following (§17.6.3 (7)):
When N is zero, the instantiation of the expansion produces an empty list. Such an instantiation does not alter the syntactic interpretation of the enclosing construct
This is why I think it is well formed.
- What do you think?
- How can I track down this ambiguity for sure? It is hard to decide, because the code compiles but it means nothing: §17.7 (8.3) is NDR, the compilers do not have to raise any compilation error.
T
beingint
is of course not the correct case in the given code. I realize that I would more or less be restating the original question in light of that ("is the set of 'every valid specialization' for a template with dependent template parameters constrained by the constraints of the dependent template parameter or are those irrelevant?"), comment deleted. – CarbonadoIsSigned
non-void, then the code is well-formed. But if there is no such specialization, then the code is ill-formed. At least, this is how I understand this, just strictly interpreting what's written. But I'm not sure, that this was the intent of the writers of the standard. – UnderproductionIsSigned
exists, it is well-formed (because such anIsSigned
specialization could exist). But I still think we should base answers on what the intent behind this rule is in the first place. – Carbonadotemplate< typename T1, typename T2, typename... TS > void f( std::pair< T1, T2, TS... > );
– Embrocation