我将使用以下示例来说明我的问题:
template<typename T>
T diff(T a, T b)
{
return a-b;
}
我希望此模板功能仅在类型T签名时有效。我能弄清楚的唯一解决方案是对所有无符号类型使用delete关键字:
template<>
unsigned char diff(unsigned char,unsigned char) == delete;
template<>
unsigned char diff(unsigned char,unsigned char) == delete;
还有其他解决方案吗?
答案 0 :(得分:45)
您可以将std::is_signed
与std::enable_if
一起使用:
template<typename T>
T diff(T a, T b);
template<typename T>
std::enable_if_t<std::is_signed<T>::value, T> diff(T a, T b) {
return a - b;
}
此std::is_signed<T>::value
true
T
当且仅当true
已签名(BTW,对于浮点类型,它也是std::is_integral
,如果您不这样做需要它,考虑与std::enable_if_t<Test, Type>
)结合使用。
std::enable_if<Test, Type>::type
与std::enable_if<Test, Type>
相同。如果Test
为false,则type
被定义为空结构,否则定义为仅具有typedef Type
等于模板参数std::enable_if_t<std::is_signed<T>::value, T>
的结构。
因此,对于签名类型,T
等于template<>
unsigned diff(unsigned, unsigned)
{
return 0u;
}
,而对于无符号,它没有定义,编译器使用SFINAE规则,因此,如果需要为a指定实现特别是非签名类型,你可以轻松地做到这一点:
/search/
答案 1 :(得分:35)
static assert
与std::is_signed
怎么样?
template<typename T>
T diff(T a, T b)
{
static_assert(std::is_signed<T>::value, "signed values only");
return a-b;
}
在那里看到它: http://ideone.com/l8nWYQ
答案 2 :(得分:11)
我会使用static_assert
一个很好的错误消息。 enable_if
只会让您的IDE遇到麻烦,并且无法使用
未找到标识符
diff
这没什么用。
为什么不喜欢这样:
#include <type_traits>
template <typename T>
T diff(T a, T b)
{
static_assert(std::is_signed< T >::value, "T should be signed");
return a - b;
}
这样,当您使用签名类型以外的其他内容调用diff
时,您将使编译器编写此类消息:
错误:T应签名
显示调用diff
的位置和值,这正是您要查找的内容。
答案 3 :(得分:7)
作为另一种选择,您可能可以使用 std :: is_signed 类型特征添加 static_assert :
template<typename T>
auto diff(T x, T y)
{
static_assert(std::is_signed<T>::value, "Does not work for unsigned");
return x - y;
}
那样:
auto x = diff(4, 2); // works
auto x = diff(4U, 2U); // does not work
答案 4 :(得分:2)
因此,我的功能存在一些问题。
首先,您的函数需要匹配所有3种类型 - 左,右和结果类型。所以signed char a; int b; diff(a-b);
没有充分理由不会工作。
template<class L, class R>
auto diff( L l, R r )
-> typename std::enable_if<
std::is_signed<L>::value && std::is_signed<R>::value,
typename std::decay<decltype( l-r )>::type
>::type
{
return l-r;
}
我想要做的第二件事就是做一个差异对象;你不能轻易地传递你的diff
函数,而高阶函数也很棒。
struct diff_t {
template<class L, class R>
auto operator()(L l, R r)const
-> decltype( diff(l,r) )
{ return diff(l,r); }
};
现在我们可以将diff_t{}
传递给算法,因为它拥有&#34;重载集&#34;在一个(普通的)C ++对象中的diff
。
现在这是严重的矫枉过正。一个简单的static_assert
也可以。
static_assert
会生成更好的错误消息,但不会使用SFINAE支持其他代码,以查看是否可以调用diff
。它只会产生一个硬错误。
答案 5 :(得分:2)
您的计划对结果有何期待?就目前而言,由于存在差异,您将返回无符号。恕我直言,这是一个等待发生的错误。
#include <type_trait>
template<typename T>
auto diff(T&& a, T&& b)
{
static_assert (std::is_unsigned<T>::value);
return typename std::make_signed<T>::type(a - b);
}
更现代的等待写这个:
inline auto diff(const auto a, const auto b)
{
static_assert ( std::is_unsigned<decltype(a)>::value
&& std::is_unsigned<decltype(b)>::value );
return typename std::make_signed<decltype(a -b)>::type(a - b);
}
[edit]我觉得有必要添加这个注释:在数学方程中使用无符号整数类型总是很棘手。上面的例子对任何数学包都是一个非常有用的附加组件,如果是现实生活中的情况,你经常不得不求助于转换以产生差异的结果signed
,或者数学不起作用。
答案 6 :(得分:-1)
#include <type_traits>
template<typename T>
std::enable_if_t<(0>-T(1)),T> diff(T a, T b)
{
return a-b;
}
使用(0&gt; -T(1)),我假设init T为-1将小于0.而无符号值不可能小于0