GNU C++ 和 Clang 中的模板实例化
Template instantiation in GNU C++ and Clang
看起来 Clang (3.8) 和 GNU C++ (4.9) 中模板实例化的规则不一样。这是一个例子:
#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;
}
这个最小的例子展示了一个模板函数,foo
,它泛化了一个类型 T
和一个自然数 N
。此函数未为 N=0
定义,因此如果以这种方式使用,我想使用 Assert
class 来发出编译器错误信号。
此代码已被 GNU 编译器(以及 Visual C++ 2015)接受,但 Clang 给出 "calling a private constructor of class Assert<false>
".
的错误
那么谁是对的?正如我所见,没有调用 foo<T,0>
,因此无需实例化此模板...
编辑:接受 Clang 对标准的解释,对模板参数强制执行编译时检查的规范方法是什么?
我相信 clang 是正确的,因为 Assert<false>
不是依赖类型。
http://en.cppreference.com/w/cpp/language/dependent_name
Non-dependent names are looked up and bound at the point of template definition. This binding holds even if at the point of template instantiation there is a better match:
不要进行无效的专业化。将它们设为通用并使用 static_assert(具有相关值)来检查无效的模板参数 types/values。 static_assert(std::is_same<T, int>::value)
或 static_assert(N != 0)
Accepting Clang's interpretation of the standard, what is a canonical way to enforce compile-time checks on template parameters?
您可以为 A<0>
删除 foo()
的 "specialization"/重载,并定义通用模板如下:
template <class T, size_t N>
T foo(A<N>) {
Assert<N != 0>();
return T(N - 1);
}
使用 C++11,您无需定义自己的静态断言,可以使用提供的语言 static_assert
:
template <class T, size_t N>
T foo(A<N>) {
static_assert(N!=0, "N must be positive");
return T(N - 1);
}
两个编译器都是正确的。像往常一样,这由 [temp.res]/8:
控制
Knowing which names are type names allows the syntax of every template
to be checked. The program is ill-formed, no diagnostic required, if:
no valid specialization can be generated for a template or a substatement of a constexpr if
statement ([stmt.if]) within a
template and the template is not instantiated, or
every valid specialization of a variadic template requires an empty template parameter pack, or
a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend
on a template parameter, or
the interpretation of such a construct in the hypothetical instantiation is different from the interpretation of the
corresponding construct in any actual instantiation of the template.
您的模板与第三个要点冲突。
至于正确的解决方案,可以使用合适的static_assert
,或者您可以显式删除不需要的重载:
template <class T>
T foo(A<0>) = delete;
前者允许更好的错误消息,后者更适合其他元编程。
看起来 Clang (3.8) 和 GNU C++ (4.9) 中模板实例化的规则不一样。这是一个例子:
#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;
}
这个最小的例子展示了一个模板函数,foo
,它泛化了一个类型 T
和一个自然数 N
。此函数未为 N=0
定义,因此如果以这种方式使用,我想使用 Assert
class 来发出编译器错误信号。
此代码已被 GNU 编译器(以及 Visual C++ 2015)接受,但 Clang 给出 "calling a private constructor of class Assert<false>
".
那么谁是对的?正如我所见,没有调用 foo<T,0>
,因此无需实例化此模板...
编辑:接受 Clang 对标准的解释,对模板参数强制执行编译时检查的规范方法是什么?
我相信 clang 是正确的,因为 Assert<false>
不是依赖类型。
http://en.cppreference.com/w/cpp/language/dependent_name
Non-dependent names are looked up and bound at the point of template definition. This binding holds even if at the point of template instantiation there is a better match:
不要进行无效的专业化。将它们设为通用并使用 static_assert(具有相关值)来检查无效的模板参数 types/values。 static_assert(std::is_same<T, int>::value)
或 static_assert(N != 0)
Accepting Clang's interpretation of the standard, what is a canonical way to enforce compile-time checks on template parameters?
您可以为 A<0>
删除 foo()
的 "specialization"/重载,并定义通用模板如下:
template <class T, size_t N>
T foo(A<N>) {
Assert<N != 0>();
return T(N - 1);
}
使用 C++11,您无需定义自己的静态断言,可以使用提供的语言 static_assert
:
template <class T, size_t N>
T foo(A<N>) {
static_assert(N!=0, "N must be positive");
return T(N - 1);
}
两个编译器都是正确的。像往常一样,这由 [temp.res]/8:
控制Knowing which names are type names allows the syntax of every template to be checked. The program is ill-formed, no diagnostic required, if:
no valid specialization can be generated for a template or a substatement of a
constexpr if
statement ([stmt.if]) within a template and the template is not instantiated, orevery valid specialization of a variadic template requires an empty template parameter pack, or
a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, or
the interpretation of such a construct in the hypothetical instantiation is different from the interpretation of the corresponding construct in any actual instantiation of the template.
您的模板与第三个要点冲突。
至于正确的解决方案,可以使用合适的static_assert
,或者您可以显式删除不需要的重载:
template <class T>
T foo(A<0>) = delete;
前者允许更好的错误消息,后者更适合其他元编程。