2014-11-02 58 views
7

C++ 11引入了统一初始化,它具有禁止隐式缩小转换的理想功能。例如,int i{2.2}应该是一个错误。如何通过非缩小转换来编写类型特征以检查类型是否可以转换为另一类型?

不幸的是,出于向后兼容的原因C++ 03,自4.7以来的GCC只给出这些警告。

GCC的documentation表明,这个扩展不SFINAE上下文适用,但它似乎是错误的:

#include <type_traits> 
#include <utility> 

template <typename From, typename To> 
class is_list_convertible_helper 
{ 
    template <typename To2> 
    static void requires_conversion(To2 t); 

    template <typename From2, typename To2, 
     typename = decltype(requires_conversion<To2>({std::declval<From2>()}))> 
    //            ^Braced initializer 
    static std::true_type helper(int); 

    template <typename From2, typename To2> 
    static std::false_type helper(...); 

public: 
    using type = decltype(helper<From, To>(0)); 
}; 

template <typename From, typename To> 
class is_list_convertible 
    : public is_list_convertible_helper<From, To>::type 
{ }; 

static_assert(!is_list_convertible<double, int>::value, 
    "double -> int is narrowing!"); 

GCC 4.9.1给出了这样的输出

$ g++ -std=c++11 foo.cpp 
foo.cpp: In substitution of ‘template<class From2, class To2, class> static std::true_type is_list_convertible_helper<From, To>::helper(int) [with From2 = double; To2 = int; <template-parameter-1-3> = <missing>]’: 
foo.cpp:18:31: required from ‘class is_list_convertible_helper<double, int>’ 
foo.cpp:22:7: required from ‘class is_list_convertible<double, int>’ 
foo.cpp:26:48: required from here 
foo.cpp:10:46: warning: narrowing conversion of ‘std::declval<double>()’ from ‘double’ to ‘int’ inside { } [-Wnarrowing] 
     typename = decltype(requires_conversion<To2>({std::declval<From2>()}))> 
              ^
foo.cpp:26:1: error: static assertion failed: double -> int is narrowing! 
static_assert(!is_list_convertible<double, int>::value, 
^ 
加入专业化的

短对于每一个缩小转换,有没有办法做到这一点?

+0

手动检查数字限制吗? – Yakk 2014-11-02 23:05:19

+0

@Yakk我会用什么检查?哪些转换是和不缩小与所涉及类型的实际范围或精度无关。 – 2014-11-02 23:13:19

+0

@Tavain除了常量规则,什么时候与精度/类型无关呢?检测float-> integer,float-> less precice float,integer-> float,integer->不是超集的整数。都看起来像类型特征和精确的东西? – Yakk 2014-11-03 00:48:33

回答

0

很简单,这是GCC中的bug。自支持-std=c++11以来,该错误一直存在(尽管它在GCC 4.6中使用-std=c++0x)。对于即将到来的GCC 5版本已经修复,但可能不会回溯到GCC 4.9。