如何强制模板参数类型进行签名?

fee*_*ree 31 c++ templates c++11 c++14

我将使用以下示例来说明我的问题:

template<typename T>
T diff(T a, T b)
{
  return a-b;
}
Run Code Online (Sandbox Code Playgroud)

我希望这个模板功能只有在签名类型T时才有效.我能想到的唯一解决方案是对所有无符号类型使用delete关键字:

template<>
unsigned char diff(unsigned char,unsigned char) == delete;
template<>
unsigned char diff(unsigned char,unsigned char) == delete;
Run Code Online (Sandbox Code Playgroud)

还有其他解决方案吗?

ale*_*in0 45

您可以std::is_signedstd::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;
}
Run Code Online (Sandbox Code Playgroud)

std::is_signed<T>::valuetrue当且仅当T有符号(BTW,它也true适用于浮点类型,如果你不需要它,考虑结合使用std::is_integral).

std::enable_if_t<Test, Type>是一样的std::enable_if<Test, Type>::type.std::enable_if<Test, Type>如果Test为false 则定义为空结构,否则定义为仅具有typedef type等于模板参数的结构Type.

因此,对于signed类型,std::enable_if_t<std::is_signed<T>::value, T>等于T,而对于unsigned,它没有定义,编译器使用SFINAE规则,因此,如果需要为特定的非签名类型指定实现,则可以轻松地执行此操作:

template<>
unsigned diff(unsigned, unsigned)
{
    return 0u;
}
Run Code Online (Sandbox Code Playgroud)

一些相关链接:enable_if,is_signed.

  • @misterwhy,同意`static_assert`在这里是可取的 (4认同)
  • 在这种情况下,我不会使用`enable_if`,因为它在编译时不提供有用的信息.只告诉你没有找到符号......在这种奇特的环境中并不酷. (2认同)

Lou*_*uen 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;
}
Run Code Online (Sandbox Code Playgroud)

在那里看到它:http: //ideone.com/l8nWYQ

  • 很好的答案,但请注意,在C++ 17中将添加没有消息的`static_assert`,这个问题用C++ 11和C++ 14标记. (5认同)
  • @December那么只添加消息会有什么问题? (4认同)
  • 我几乎总是喜欢`static_assert`到SFINAE,因为它会产生更好的错误信息.OTOH,一个`static_assert`意味着你将来不能SFINAE关闭这个功能.至少,我认为大多数公共API函数应该是`static_assert`s (3认同)

mis*_*why 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;
}
Run Code Online (Sandbox Code Playgroud)

这样,当你diff使用其他东西而不是签名类型调用时,你将让编译器编写这种消息:

错误:T应签名

与调用的位置和值diff,这正是您正在寻找的.


Edg*_*jān 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;
}
Run Code Online (Sandbox Code Playgroud)

以便:

auto x = diff(4, 2); // works
auto x = diff(4U, 2U); // does not work
Run Code Online (Sandbox Code Playgroud)