Creating a template instance in GNU C ++ and Clang

It seems that the rules for the template instance in Clang (3.8) and GNU C ++ (4.9) do not match. Here is an example:

#include <cstddef> template <bool> class Assert { Assert(); // private constructor for Assert<false> }; template <> class Assert<true> { // implicit public constructor for Assert<true> }; template <size_t N> class A { }; template <class T, size_t N> T foo(A<N>) { return T(N - 1); } template <class T> T foo(A<0>) { // foo is not defined for N=0 Assert<false>(); return T(0); } int main(int argc, char **argv) { foo<int>(A<3>()); return 0; } 

This minimal example shows a template function foo that generalizes to type T and a positive integer N This function is not defined for N=0 , so I would like to use the Assert class to signal a compiler error if it is used this way.

This code is accepted by the GNU compiler (as well as Visual C ++ 2015), but Clang gives an error for "invoking the private constructor of the Assert<false> class."

So who is right? As I see, there is no call to foo<T,0> , so there is no need to instantiate this template ...

EDIT: Accepting an interpretation of the standard Clang standard, what is the canonical way to force control over template parameters at compile time?

+7
c ++ gcc instantiation templates clang ++
source share
3 answers

I believe clang is true, since Assert<false> not a dependent type.

http://en.cppreference.com/w/cpp/language/dependent_name

Independent names are scanned and anchored at the template definition point. This binding is performed even if at the moment of creating the template there is a better match:

Do not do specialization that cannot be valid. Make them public and use static_assert (with a dependent value) to check for invalid types / values โ€‹โ€‹of template arguments. static_assert(std::is_same<T, int>::value) or static_assert(N != 0)

+5
source share

Accepting an interpretation of the standard Clang standard, what is the canonical way to force a check for template parameters at compile time?

You can discard the "specialization" / overload foo() for A<0> and define a generic pattern as follows:

 template <class T, size_t N> T foo(A<N>) { Assert<N != 0>(); return T(N - 1); } 

With C ++ 11, you do not need to define your own static statement and use the specified language static_assert :

 template <class T, size_t N> T foo(A<N>) { static_assert(N!=0, "N must be positive"); return T(N - 1); } 
+5
source share

Both compilers are correct. As usual, this is controlled by [temp.res] / 8 :

Knowing the names of type name names allows you to use the syntax of each template to be checked. The program is poorly formed, diagnostics are not required if:

  • no valid specialization can be generated for the template or substitution of the constexpr if ([stmt.if]) operator within the template and template are created, or

  • any actual specialization of the variational template requires an empty package of template parameters or

  • a hypothetical template creation immediately after its determination will be poorly formed due to a design that does not depend on the template parameter or

  • the interpretation of such a construct in a hypothetical instance is different from the interpretation of the corresponding construct in any actual instance of the pattern.

Your template starts from the third point.

As for the correct solution, you can either use the appropriate static_assert , or you can explicitly remove the unwanted overload:

 template <class T> T foo(A<0>) = delete; 

The former allows better reporting of errors; the latter is better combined with other metaprogramming.

+5
source share

All Articles