C ++ 11 introduces a unified initialization that comes with the desired feature of prohibiting implicit conversion narrowing. For example, int i{2.2} should be an error.
Unfortunately, for reasons of backward compatibility with C ++ 03, GCC with 4.7 gives only a warning for them.
GCC indicates that this extension does not apply in SFINAE contexts, but it seems to be wrong:
#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 gives this output
$ 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, ^
With the exception of adding specializations for each narrowing transformation, is there a way to make this work?
c ++ gcc c ++ 11 typetraits sfinae
Tavian barnes
source share