在SFINAE中将int缩小为bool,gcc和clang之间的输出不同 [英] Narrowing int to bool in SFINAE, different output between gcc and clang

查看:53
本文介绍了在SFINAE中将int缩小为bool,gcc和clang之间的输出不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下示例:

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".

Clang (3.4.1) outputs "-1, -1", while GCC(4.9.0) outputs "-1, 42".

问题在于 pick 的专业化.虽然Gcc似乎很乐意将 is_nice< T> :: value (42)转换为 bool(true),但是clang却不这样做,并放弃了专业化.这两个示例均使用 -std = c ++ 11 编译.

The problem lays in the specialization of pick. While Gcc seems happy to convert is_nice<T>::value (42) to bool(true), clang does not do so, and discards the specialization. Both examples compiled with -std=c++11.

哪个编译器是正确的?

推荐答案

这是gcc错误 57891 .将整数常量 42 转换为 bool 涉及缩小转换,这是非类型模板参数所不允许的.因此, enable_if 的格式不正确,应该丢弃 pick 的专业化名称,就像clang正确进行的那样.

This is gcc bug 57891. Conversion of the integral constant 42 to bool involves a narrowing conversion, which is not allowed in non-type template arguments. Hence the enable_if is ill-formed, and the pick specialization should be discarded, as clang correctly does.

§14.3.2/5 [temp.arg.nontype]

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

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]

... 类型为 T 转换后的常量表达式是一个隐式转换为类型为 T <的prvalue的表达式./code>,其中转换后的表达式为核心常数表达式和隐式转换序列仅包含用户定义的转换,左值到右值转换(4.1),积分提升(4.5)和积分转换(4.7),而不是缩小转换范围(8.5.4).

... 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.


最小示例演示了gcc错误:

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

int main() {}

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

gcc-4.9 accepts the code while clang-3.4 rejects it with the following error:

错误:非类型模板参数的计算结果为10,无法将其范围缩小为'bool'[-Wc ++ 11-narrowing]

error: non-type template argument evaluates to 10, which cannot be narrowed to type 'bool' [-Wc++11-narrowing]

 foo<10> f;
     ^


轻松解决您的特定问题.确保 enable_if 的非类型模板参数的计算结果为 bool


The fix to your particular problem is easy. Make sure the non-type template argument to enable_if evaluates to a 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;
};

这篇关于在SFINAE中将int缩小为bool,gcc和clang之间的输出不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆