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,
^
加入專業化的
短對於每一個縮小轉換,有沒有辦法做到這一點?
手動檢查數字限制嗎? – Yakk 2014-11-02 23:05:19
@Yakk我會用什麼檢查?哪些轉換是和不縮小與所涉及類型的實際範圍或精度無關。 – 2014-11-02 23:13:19
@Tavain除了常量規則,什麼時候與精度/類型無關呢?檢測float-> integer,float-> less precice float,integer-> float,integer->不是超集的整數。都看起來像類型特徵和精確的東西? – Yakk 2014-11-03 00:48:33