g++ and clang++ different behaviour with integral template parameter - c++

I have the following C++11 code.
#include <type_traits>
using IntType = unsigned long long;
template <IntType N> struct Int {};
template <class T>
struct is_int : std::false_type {};
template <long long N>
struct is_int<Int<N>> : std::true_type {};
int main()
{
static_assert (is_int<Int<0>>::value, "");
return 0;
}
Clang++ 3.3 compiles the code but on g++ 4.8.2 static assertion fails
$ g++ -std=c++11 main.cpp
main.cpp: In function ‘int main()’:
main.cpp:15:5: error: static assertion failed:
static_assert (is_int<Int<0>>::value, "");
^
$
The problem is caused by different integral template parameters.
Which compiler is right in this case?

The surprise
This is a subtle Clang bug, deeply buried in the Standard. The problem is that in almost all cases, non-type template arguments can be converted to the type of the template parameter. E.g. the expression Int<0> has an int literal argument of value 0 that is being converted to the type unsigned long long of the template parameter N.
14.8.2 Template argument deduction [temp.deduct]/2 2nd bullet
-- Non-type arguments must match the types of the corresponding non-type
template parameters, or must be convertible to the types of the
corresponding non-type parameters as specified in 14.3.2, otherwise
type deduction fails.
Since your class template is_int<T> has a partial specialization, we need to look at
14.5.5.1 Matching of class template partial specializations [temp.class.spec.match]
1 When a class template is used in a context that requires an
instantiation of the class, it is necessary to determine whether the
instantiation is to be generated using the primary template or one of
the partial specializations. This is done by matching the template
arguments of the class template specialization with the template
argument lists of the partial specializations.
2 A partial specialization matches a given actual template argument
list if the template arguments of the partial specialization can be
deduced from the actual template argument list (14.8.2).
So it would seem that we can proceed to the earlier quote of 14.8.2/2 2nd bullet and match the second specialization (although in that case an even more complicated overload resolution game would have to be played).
The resolution
However, it turns out (as mentioned by #DyP in the comments) that another clause in the Standard supersedes this:
14.8.2.5 Deducing template arguments from a type [temp.deduct.type]
17 If, in the declaration of a function template with a non-type
template-parameter, the non-type templateparameter is used in an
expression in the function parameter-list and, if the corresponding
template-argument is deduced, the template-argument type shall match
the type of the template-parameter exactly, except that a
template-argument deduced from an array bound may be of any integral
type. [ Example:
template<int i> class A { / ... / };
template<short s> void f(A<s>);
void k1() {
A<1> a;
f(a); // error: deduction fails for conversion from int to short
f<1>(a); // OK
}
The upshot is that the partial specialization of is_int cannot be deduced because it does not take the exact same type (unsigned long long vs long long) as the Int class template's formal non-type template parameter.
You can resolve this by giving the non-type template parameter N in the partial specialization of is_int the same type as the non-type parameter N in the primary template Int.
template <IntType N>
// ^^^^^^^^
struct is_int<Int<N>> : std::true_type {};
Live Example.

Clang is being inconsistent. Since it accepts your code, I'm expecting the following code must output f(Int<long long>) instead of f(T):
using IntType = unsigned long long;
template <IntType N> struct Int {};
template<typename T>
void f(T) { std::cout << "f(T)" << std::endl; }
template<long long N>
void f(Int<N>) { std::cout << "f(Int<long long>)" << std::endl; }
int main()
{
f(Int<0>{});
}
But surprisingly, it outputs this (online demo):
f(T)
That shows Int<0> does NOT match with the second overload which accepts the argument as Int<N>. If that is so, then why does it match with Int<N> when it is used as template argument to the class template (in your case)?
My conclusion:
If Clang is correct in my case, then it is incorrect in your case.
If Clang is correct in your case, then it is incorrrect in my case.
Either way, Clang seems to have bug.
GCC, on the other hand, is consistent at least. That doesn't prove though that it doesn't have bug — it might mean that it has bug in both cases! Unless someone comes up with the standardese and showing it has bug too, I'm going to trust GCC in this case.

Related

C++20 NTTP specialization

There is disagreement between gcc/clang and msvc when trying to compile the following code:
struct foo {
};
// primary template
template<auto>
struct nttp {
static constexpr int specializaion = 0;
};
// specialization
template<foo f>
struct nttp<f> {
static constexpr int specializaion = 1;
};
int main() {
// Does not compile with msvc 19.30
nttp<5> x{};
}
Full example here.
Msvc is complaining that there is no viable conversion from int to foo which is obviously true, but shouldn't be of any relevance here as far as I understand the rules of partial template specialization.
Quoting cppreference:
When a class or variable (since C++14) template is instantiated, and there are partial specializations available, the compiler has to decide if the primary template is going to be used or one of its partial specializations.
If only one specialization matches the template arguments, that specialization is used
If more than one specialization matches, partial order rules are used to determine which specialization is more specialized. The most specialized specialization is used, if it is unique (if it is not unique, the program cannot be compiled)
If no specializations match, the primary template is used
I'd argue that there is no matching spezialization for int in this case hence the primary template should be selected.
Interestingly, the situation can be fixed by constraining the auto in the specialization by a concept:
template<class T>
concept Foo = std::is_same_v<T, foo>;
template<auto>
struct nttp {
static constexpr int specializaion = 0;
};
template<Foo auto f>
struct nttp<f> {
static constexpr int specializaion = 2;
};
// compiles with all compilers
static_assert(nttp<5>{}.specializaion == 0);
Function templates work as expected, too:
constexpr int test(auto) {
return 0;
}
constexpr int test(foo) {
return 1;
}
// compiles with all compilers
static_assert(test(5) == 0);
Long story short: empirically and intuitively I'd say that this is a bug in MSVC, but as always there's a chance that UB is involved here. So the question would be: are clang/gcc correct, or MSVC, or even all of them?
This is open MSVC bug report:
Specialization of class template with auto parameter fails to compile for an unclear reason
Your program is well-formed as per [temp.class.spec.match]/2 and [temp.class.spec.match]/3:
/2 A partial specialization matches a given actual template argument
list if the template arguments of the partial specialization can be
deduced from the actual template argument list, and the deduced
template arguments satisfy the associated constraints of the partial
specialization, if any.
/3 If the template arguments of a partial specialization cannot be
deduced because of the structure of its template-parameter-list and
the template-id, the program is ill-formed.
/3 was specifically updated as part of P0127R2 (Declaring non-type template parameters with auto), which re-wrote the previously revised wording from the resolution of CWG1315
(After CWG1315, before P0123R2) /3 Each template-parameter shall appear at least once in the template-id outside a non-deduced context.
This re-write was done particularly to allow partial specialization over non-template parameters declared with the auto placeholder type.

Template parameters of function type with auto return type arguments of previous template parameter types

I have a template with two parameters: the first is a type, and the second is a function pointer with an argument whose type is the first template parameter. This MCVE works:
void returnsVoid(int x) { }
template <typename T, void (*Func)(T)>
struct foo { void bar(T t) { Func(t); } };
int main(int, char *[]) {
foo<int, returnsVoid> a; // ok
}
However, when I change the return type of the second template parameter to auto (as explained in this related question), I get an error:
void returnsVoid(int x) { }
template <typename T, auto (*Func)(T)>
struct foo {
void bar(T t) { Func(t); }
};
int main(int, char *[]) {
foo<int, returnsVoid> a; // error: unable to deduce ‘auto (*)(T)’ from ‘returnsVoid’
// note: mismatched types ‘T’ and ‘int’
}
Why does this no longer work with an auto return type?
I'm using g++ 9.3.0 on an Ubuntu Linux machine. A similar error occurs in clang 10.
This is gcc's bug. (Bug 83417)
It seems gcc failing deducing the type of auto when using the 1st template parameter T as function parameter; you can use std::type_identity (since C++20) to exclude it from participating in template argument deduction.
// workaround for gcc
template <typename T, auto (*Func)(std::type_identity_t<T>)>
struct foo {
void bar(T t) { Func(t); }
};
LIVE
BTW: Clang 10 seems working well.
All standard references below refer, unless noted otherwise, to N4861 (March 2020 post-Prague working draft/C++20 DIS).
TL;DR;
Jump to the A workaround to mitigate the GCC bug section in the bottom of this post for a workaround, accepted by GCC and Clanng, which still relies of deduction of dependent types to avoid a client having to specify a second template argument for the actual type of the function parameter associated with the "main" template argument; namely the function pointer used associated non-type template parameter.
Standardese
As per [temp.deduct.type]/13:
When the value of the argument corresponding to a non-type template
parameter P that is declared with a dependent type is deduced from
an expression, the template parameters in the type of P are deduced
from the type of the value. [ Example:
template<long n> struct A { };
template<typename T> struct C;
template<typename T, T n> struct C<A<n>> {
using Q = T;
};
using R = long;
using R = C<A<2>>::Q; // OK; T was deduced as long from the
// template argument value in the type A<2>
— end example ]
any dependent types in the declaration of a non-type template parameter that undergoes type deduction (from an expression) shall also be deduced from the associated argument for the non-type template parameter. It is also essential that [temp.deduct.type]/5, covering the non-deduced contexts, does not apply for general uses of dependent types within non-type template parameters that are function pointers; meaning in the OP's example, T is a dependent type and is thus deduced from the value of the argument to the non-type (function pointer) template parameter.
A common problem when a given, say, type template parameter is deduced from more than one source (e.g. as in the example of OP), is that deduction yields different types; e.g. as showing in the following blog post:
template<typename T>
struct Foo { T t; };
template<typename T>
void addToFoo(Foo<T>& foo, T val) { foo.t += val; }
int main() {
Foo<long> f{42};
addToFoo(f, 13); // error: no matching function for call to 'addToFoo'
// note: candidate template ignored: deduced conflicting
// types for parameter T (long vs. int).
return 0;
}
As has been shown in #songyuanyao: answer (and as is shown also in the blog post), a type identity transformation trait can be used to intentionally place a given template parameter in a non-deduced context for cases where several deduction sources yields conflicting results.
However, the root cause of OP:s failure is not conflicting deduction results (this is a red herring), but rather GCC:s failure to correctly deduce template parameter from when another template parameter is deduced, where the former is present as a dependent type.
Thus, if we go back to [temp.deduct.type]/13, for the following class template and subsequent partial specialization:
// #1
template <auto>
struct A { static void dispatch() = delete; };
// #2
template <typename T, void (*fun)(T)>
struct A<fun> {
static void dispatch() {
T t{};
fun(t);
}
};
the following:
A<f>::dispatch(); // #3
is well-formed if f is a function with a single argument (of a type that is default-constructible) which returns void, e.g.
void f(int) { std::cout << "void f(int)\n"; }
// -> #3 is well-formed
as this will match the partial specialization at #2, deducing T to int and the non-type template parameter (which decides the specialization blueprinted by the primary template), which is dependent on T in this partial specialization, to void(*)(int).
On the other hand, #3 is ill-formed if f does not return void, as the partial specialization at #2 is no longer viable.
void f(int) { std::cout << "int f(int)\n"; }
// -> #3 is ill-formed
The key here is that:
the partial specialization at #2 applies only for template arguments to A which match the second (non-type) template parameter of the specialization, and
the first template parameter of the specialization,T, is deduced from the deduction of the second (non-type) template parameter, as T is a dependent type in the declaration of the second template parameter.
Both GCC and Clang works as expected for the two cases above.
Now, if we consider the similar example as to that of #1 and #2 above:
// #4
template <auto>
struct B { static void dispatch() = delete; };
// #5
template <typename T, auto (*fun)(T)>
struct B<fun> {
static void dispatch() {
T t{};
fun(t);
}
};
// ... elsewere
// #6
B<f>::dispatch();
the same argument as above applies:
if template argument f refers to a function (now with less restrictions) that has a single argument (of a type that is default-constructible), then the partial specialization at #5 is viable, and its second non-type template parameter, which contains its first type template parameter as a dependent type, shall be used to deduce the latter.
The significant difference in this case is that the type of the non-type template parameter itself undergoes [temp.arg.nontype]/1:
If the type T of a template-parameter contains a placeholder type
([dcl.spec.auto]) or a placeholder for a deduced class type
([dcl.type.class.deduct]), the type of the parameter is the type
deduced for the variable x in the invented declaration
T x = template-argument ;
If a deduced parameter type is not permitted for a template-parameter
declaration ([temp.param]), the program is ill-formed.
but [temp.deduct.type]/13 still applies the same, and we may not that [temp.deduct.type]/13 was actually added as part of P0127R2 (Declaring non-type template parameters with auto) which introduced placeholder types for non-type template parameters for C++17.
Thus, the core issue is that GCC fails to perform dependent type deduction (as specified in [temp.deduct.type]/13) when the non-type template parameter in whose declaration the dependent type (to be deduced) is present is a function pointer (or, as shown in the linked to GCC bug report, as pointer to member) AND the non-type template parameter is declared with a placeholder type (auto).
#songyuanyao: answer shows a workaround to this bug, applied to OP's example, simply making the dependent type non-dependent, as the associated template parameter can be deduced from elsewhere (namely from the first template argument in OP's example). This would not work for the examples above, where we rely solely on the dependent type deduction in the deduction of the non-type template parameter to find the type of the type template parameter (which is the dependent type in the former).
For an actual client API, requiring the client to explicitly specify the type of the argument to the function which is provided as another argument, when the former is entirely deducible from the latter, is arguably redundant design, and opens up for client confusion when providing conflicting arguments for these two template parameters. Thus, we'd arguably like to fall back on the partial specialization technique shown above, but as shown in these answers, GCC fails us in this regard in case we'd like the client to not be restricted to a specific return type.
A workaround to mitigate the GCC bug
We can work our way around this, however, by using the same approach as above, still relying on [temp.deduct.type]/13, but by using an additional type template parameter (for the return type) in the partial specialization:
#include <iostream>
template <auto>
struct C { static void dispatch() = delete; };
template <typename T, typename Return, Return (*fun)(T)>
struct C<fun> {
static void dispatch() {
T t{};
fun(t);
}
};
void f(int) { std::cout << "void f(int)\n"; }
int g(int) { std::cout << "int f(int)\n"; return 0; }
int main() {
C<f>::dispatch();
C<g>::dispatch();
}
The client will not need to worry about the additional template parameters of the partial specialization, as they entirely deducible via the third non-type template parameter of the specialization, in whose declaration they are dependent. This final example is accepted by both GCC and Clang.
This is CWG2476: [dcl.spec.auto]/2 requires that auto used as (part of) a return type without a trailing-return-type appear only where the function declarator declares a function. The template parameter declaration doesn’t do that, so it’s invalid. One could argue that /5 allows it in a template parameter’s decl-specifier-seq regardless, but that doesn’t make sense because it would deprive the following of meaning:
template<auto g() -> int>
int f() {return g();}
That said, the deduction rules would work here, so this is a defect in the wording that will probably be fixed by saying that return type deduction just doesn’t happen in the cases where auto is allowed for other reasons.
As already stated by #songyuanyao this seems to be a gcc bug.
For <= c++17 One solution is to move type T form function signature to non-deduced context:
template <typename T>
struct identity { using type = T; };
and then
template <typename T, auto (*Func)(typename identity<T>::type)>
struct foo {
void bar(T t) { Func(t); }
};
Another approach is to change design and to move to a member function template. The auto type deduction works in this case:
void returnsVoid(int) { }
template <typename T>
struct foo {
template <auto (*Func)(T)>
void bar(T t) { Func(t); }
};
int main(int, char *[]) {
foo<int> a;
a.bar<returnsVoid>(3);
}
Live

Function template overloading with variadic templates: Intel c++ compiler version 18 produces different result from other compilers. Is intel wrong?

Consider the following code snippet:
template<typename T, template<typename, typename ...> class A, typename ... Ts>
int a(A<T, Ts...> arg){
return 1; // Overload #1
}
template<typename A>
int a(A arg) {
return 2; // Overload #2
}
template<typename T>
struct S{};
int main() {
return a(S<int>());
}
Upon calling function a with an instance of a template class, I expect the compiler to select the more special function overload #1. According to the compiler explorer, clang, gcc and intel up to version 17 actually do select overload #1. In contrast, later intel compiler versions (18 and 19) select overload #2.
Is the code ill-defined or are the more recent intel compiler versions wrong?
The following fails to call a() on icc 19.01:
template<template<typename, typename ...> class A, typename T, typename ... Ts>
int a(A<T, Ts...> arg){
return 1;
}
template<typename T>
struct S{};
int foo()
{
return a(S<int>());
}
It simply can't consider that a() as a candidate, and that's why the overloading is different in the question.
C++17 draft says:
(where P is the template-template parameter, and A is the instantiating argument)
17.3.3 Template template arguments
A template-argument matches a template template-parameter P when P is at least as specialized as the
template-argument A. If P contains a parameter pack, then A also matches P if each of A’s template parameters
matches the corresponding template parameter in the template-head of P.
So far so good, <int argument head matches the parameter head <T.
Two template parameters match
if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are
equivalent (17.6.6.1), and for template template-parameters, each of their corresponding template-parameters
matches, recursively.
Still looks good, int and T match.
When P’s template-head contains a template parameter pack (17.6.3), the template
parameter pack will match zero or more template parameters or template parameter packs in the template-head
of A with the same type and form as the template parameter pack in P (ignoring whether those template
parameters are template parameter packs).
This is more difficult to parse, but yet it seems OK to me. From what I understand, the compiler should have matched the argument with the template-template parameter. It explicitly talks about zero or more, and we have zero here.

Why doesn't C++ allow two function/class templates with the same name, differing only by the type of a non-type template parameter (of integral type)?

The compiler gives an error when I try this. I tried with both VC++ and g++.
This applies equally to function templates and class templates (though for function templates the compiler error only occurs if and when the function template is instantiated; the compiler error for class template occurs immediately when the compiler encounters the second class definition).
Here is an example for a function template:
template <unsigned int>
void Foo() {}
template <signed int> // Same name, only difference is the type of the
void Foo() {} // non-type template parameter (of integral type)
Foo<10U>(); // COMPILER ERROR.
Above, why can't the compiler just instantiate Foo<unsigned int>()?
I found that this is not an issue if the second version of the template function/class has a type template parameter. It also is not an issue if the second version of the template function/class has or a non-type template parameter of non-integral type:
template <unsigned int>
void Foo() {}
template <unsigned int*> // Non-type template parameter
void Foo() {} // of non-integral type
template <typename T> // Type template parameter
void Foo() {}
Foo<10U>(); // OK
So if I had to guess I'd say it has something to do with the fact that the compiler can convert between values of integral types? But that doesn't stop C++ from allowing two overloading functions that differ only by the type of on integral parameter.
It does allow it, you were able to write the two templates just fine. They just become unusable when instantiated. The reason is that there is no "overload resolution" to choose a template. The only requirement imposed on a non-type template argument is as follows:
[temp.arg.nontype]/2
A template-argument for a non-type template-parameter shall be a
converted constant expression of the type of the template-parameter.
And 10u is a converted constant expression of both int and unsigned int type. Valid as an argument for either overload.

Can C++17's deduced `auto` non-type `template` parameters pattern-match templates with explicit non-type parameters?

Consider this example (also available on wandbox):
template <template <auto> class>
void test() { }
template <int>
struct X { };
Trying to instantiate test<X>() on clang++ 4.0 (trunk) results in a compilation error:
error: no matching function for call to 'test'
test<X>();
^~~~~~~
note: candidate template ignored:
invalid explicitly-specified argument for 1st template parameter
void test() { }
My initial assumption/intuition was that test could be used to match any template having a non-type parameter.
However, the following code snippet successfully compiles:
template <template <auto> class>
void test() { }
// vvvv
template <auto>
struct X { };
Is this intended? Could not find anything conclusive in P0127R2.
It's definitely intended. Template-template parameters can only match templates which take the same kinds of arguments. This:
template <template <auto> class>
void test() { }
can only be instantiated with a class template that can take any kind of non-type parameter. But this:
template <int>
struct X { };
is not such a class template. X can only be instantiated with an int. It simply does not match the specification for the template template parameter, hence the error. What if test wanted to instantiate its class template with a pointer type? Or pointer to function or pointer to member? That would be impossible.
Your second attempt, with template <auto> struct X { }; does match the template-template parameter, hence is well-formed. Note also that the reverse, having test take a template <int> class parameter and passing in template <auto> struct X { }; is also well-formed as the argument is more general than the parameter.
The relevant wording is in [temp.arg.template]:
A template-argument matches a template template-parameter P when each of the template parameters in the template-parameter-list of the template-argument’s corresponding class template or alias template A matches
the corresponding template parameter in the template-parameter-list of P. Two template parameters match if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are
equivalent (14.5.6.1), and for template template-parameters, each of their corresponding template-parameters matches, recursively.
Note: the equivalence wording accepts the auto - auto case and rejects the auto - int case, but also seems to reject the int - auto case (based on my reading). I'm going to try to get some clarification on it.
In addition to Barry's answer, which made me curious, here are the four possible combinations and results using Clang 4.0 (SVN), see also on wandbox:
template <bool> struct obj_bool { }; // object taking a value of boolean type
template <auto> struct obj_auto { }; // object taking a value of deduced type
// ^^^^^^ Note: this is a template value argument (non-type template argument)
template <template <auto> typename> void fn_auto() { }
template <template <bool> typename> void fn_bool() { }
// ^^^^^^^^^^^^^^^^^^^^^^^^ Note: this is a template type argument
// ^^^^^^ taking a template value argument
int main() {
fn_bool<obj_bool>(); // #1 bool->bool OK (exact match)
fn_auto<obj_auto>(); // #2 auto->auto OK (exact match)
fn_bool<obj_auto>(); // #3 bool->auto OK (sub-set)
//fn_auto<obj_bool>(); // #4 auto->bool Error: no matching function.
}
From that, #1 and #2 are obviously exact matches and are working as expected. #3 would invoke the bool implementation on a template that can handle not only bool but all types, whereas #4 would try to invoke a definition expecting a generalized object (auto) with an object providing only a sub-set (bool) of possibilities.
The templated function fn_auto promises possible instantiations for templates taking any value type (auto). Thus giving it only a sub-set of possibilities (bool) violates this promise.
Though not immediately obvious, the restriction makes sense. And sorry for my wording not being C++ Standard compliant.