考虑以下示例:
template<int i>
struct nice_type;
template<class T>
struct is_nice : std::false_type {};
template<int i>
struct is_nice< nice_type<i> > : std::integral_constant<int, i> {};
template<class T, class = void>
struct pick
{
typedef std::integral_constant<int, -1> type;
};
template<class T>
struct pick<T, typename std::enable_if< is_nice<T>::value >::type >
{
typedef std::integral_constant<int, is_nice<T>::value > type;
};
int main()
{
std::cout << pick<int>::type::value << ", ";
std::cout << pick< nice_type<42> >::type::value << std::endl;
return 0;
}
Clang (3.4.1) 输出“-1, -1”,而 GCC(4.9.0) 输出“-1, 42”。
问题在于pick
的特化.虽然 Gcc 似乎很乐意转换 is_nice<T>::value
(42) 至 bool(true)
, clang 不这样做,并丢弃特化。这两个示例都是用 -std=c++11
编译的.
哪个编译器是正确的?
最佳答案
这是 gcc 错误 57891 .整数常量 42
到 bool
的转换涉及收缩转换,这在非类型模板参数中是不允许的。因此 enable_if
格式错误,pick
特化应该被丢弃,就像 clang 正确做的那样。
§14.3.2/5 [temp.arg.nontype]
The following conversions are performed on each expression used as a non-type template-argument. If a non-type template-argument cannot be converted to the type of the corresponding template-parameter then the program is ill-formed.
— For a non-type template-parameter of integral or enumeration type, conversions permitted in a converted constant expression (5.19) are applied.
...
§5.19/3 [expr.const]
...
A converted constant expression of typeT
is an expression, implicitly converted to a prvalue of typeT
, where the converted expression is a core constant expression and the implicit conversion sequence contains only user-defined conversions, lvalue-to-rvalue conversions (4.1), integral promotions (4.5), and integral conversions (4.7) other than narrowing conversions (8.5.4).
§8.5.4/7 [dcl.init.list]
A narrowing conversion is an implicit conversion
...
— from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.
这minimal example演示 gcc 错误:
template<bool>
struct foo{};
foo<10> f;
int main() {}
gcc-4.9 接受代码,而 clang-3.4 拒绝它并出现以下错误:
error: non-type template argument evaluates to 10, which cannot be narrowed to type 'bool' [-Wc++11-narrowing]
foo<10> f; ^
解决您的特定问题很容易。确保 enable_if
的非类型模板参数计算为 bool
template<class T>
struct pick<T, typename std::enable_if< is_nice<T>::value != 0 >::type >
// ^^^^^^
{
typedef std::integral_constant<int, is_nice<T>::value > type;
};
关于c++ - 在 SFINAE 中将 int 缩小为 bool,gcc 和 clang 之间的输出不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24345399/