2016-04-15 69 views
0

我可以对模板变量使用enable_if(或者是否存在一些替代技术)。例如可变模板和std :: enable_if

typedef float Float; 
typedef double Double; 

template<class T> 
constexpr Bool IsFloat = std::is_same_v<T, Float>; 

template<class T> 
constexpr Bool IsDouble = std::is_same_v<T, Double>; 

template<class T> 
constexpr Bool IsFloatingPoint = IsFloat<T> || IsDouble<T>; 

template<class T> 
using EnableIfFloatingPoint = std::enable_if_t<IsFloatingPoint<T>>; 

template 
< 
    class T, 
    typename = EnableIfFloatingPoint<T> 
> 
constexpr T Pi = T(3.1415926535897932384626433832795); 

Visual Studio中给了我一个编译器错误说“太少模板参数”当我尝试使用Pi<float>,例如。

+0

有点困惑为什么你没有在这篇文章中加入IsFloatingPoint。 – WhozCraig

+0

@WhozCraig因为现在有两倍的代码,而且大部分代码都是不相关的。 – user673679

+0

SFINAE的概念对变量模板没有意义,因为它们既不能过载也不能部分专用。 – Brian

回答

2

马上我推荐使用std::is_floating_point而不是手动滚动您自己的浮点检测机制。另外,从C++ 17开始,您将可以使用_v后缀代替::value

正如在一些评论中提到的那样,在变量模板上使用SFINAE本身没什么意义,但是您可以通过尝试来实现只允许浮点类型取值为Pi的解决方案将变量模板设置为std::enable_if_t< std::is_floating_point<T>::value, T>,如果条件满足,这当然只有推导类型。

template<class T> 
using EnableIfFloatingPoint = std::enable_if_t<std::is_floating_point<T>::value, T>; 

template<class T> 
constexpr T Pi = EnableIfFloatingPoint<T>(3.1415926535897932384626433832795); 

Pi<T>对于整型T将只是无法编译,因为 EnableIfFloatingPoint<T>不会有任何类型的推断,但我不会考虑这个SFINAE。

更好的解决方案是将constexpr函数模板与适当的static_assert消息验证模板是否使用“正确”类型实例化。

template<class T> 
constexpr T Pi() 
{ 
    using is_fp = std::is_floating_point<T>; 
    static_assert(is_fp::value, "Pi must be instantiated with floating point types."); 
    return T{3.1415926535897932384626433832795}; 
} 
相关问题