【问题标题】:Narrowing int to bool in SFINAE, different output between gcc and clang在 SFINAE 中将 int 缩小为 bool,gcc 和 clang 之间的输出不同
【发布时间】:2014-08-12 06:45:43
【问题描述】:

考虑以下示例:

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&lt;T&gt;::value (42) 转换为 bool(true),但 clang 并没有这样做,并且放弃了专业化。两个例子都是用-std=c++11编译的。

哪个编译器是正确的?

【问题讨论】:

  • 第 8 行的意思是 nice_type 而不是 cool_type

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


【解决方案1】:

这是 gcc 错误57891。整数常量42bool 的转换涉及缩小转换,这在非类型模板参数中是不允许的。因此,enable_if 格式不正确,应丢弃 pick 特化,就像 clang 正确的做法一样。

§14.3.2/5 [temp.arg.nontype]

对每个用作 非类型模板参数。如果一个非类型 template-argument 不能 转换为相应 template-parameter 的类型,然后 程序格式错误。
— 对于一个非类型的 template-parameter 整数或枚举类型,转换后允许的转换 应用了常量表达式 (5.19)。
...

§5.19/3 [expr.const]

...T 类型的转换后的常量表达式 是一个表达式,隐式转换为T 类型的纯右值,其中转换后的表达式是核心 常量表达式和隐式转换序列仅包含用户定义的转换、左值到右值的转换 (4.1)、整型提升 (4.5) 和 整型转换 (4.7) 窄化转换除外 (8.5.4)。

§8.5.4/7 [dcl.init.list]

窄化转换是隐式转换
...
— 从整数类型或无作用域枚举类型到不能表示原始类型的所有值的整数类型,除非源是常量表达式,其值在整数提升后将适合目标类型。


这个minimal example 演示了 gcc 错误:

template<bool>
struct foo{};
foo<10> f;

int main() {}

gcc-4.9 接受该代码,而 clang-3.4 拒绝它并出现以下错误:

错误:非类型模板参数计算结果为 10,无法将其缩小为类型 '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;
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    • 2014-09-08
    • 2017-10-09
    • 2014-04-11
    相关资源
    最近更新 更多