c++ - 在 SFINAE 中将 int 缩小为 bool,gcc 和 clang 之间的输出不同

标签 c++ gcc c++11 clang sfinae

考虑以下示例:

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 .整数常量 42bool 的转换涉及收缩转换,这在非类型模板参数中是不允许的。因此 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 type T is an expression, implicitly converted to a prvalue of type T, 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/

相关文章:

c++ - 计算机图形学中的最大凸面修补

c++ - 如何获取 Windows 控制台高度?

c++ - 遍历二维数组的所有子数组

c++ - 什么是流?标准事物及其用法。

c++ - gcc/linux : CppuTest shows memory leak using static vectors, 误报?

c++ - __attribute__((optimize(0))) 适用于 "recursively"吗?

c - 你如何在automake中设置库的顺序?

C++11 线程 : Object with arguments in the constructor

c++ - if 语句中的相等比较

c++ - std::async 在 c++11 和 linux 平台中不起作用