如何一次为多种类型专门化方法

mxm*_*nkn 5 c++ templates c++11

我有这样的代码:

template< class T >
struct Value
{
    /* quite a lot of other functions which I do not want to specialize, too */
    void print( void );
};

template<> void Value<          short int >::print() { std::cout << "is integral" << std::endl; }
template<> void Value<                int >::print() { std::cout << "is integral" << std::endl; }
template<> void Value<           long int >::print() { std::cout << "is integral" << std::endl; }
template<> void Value< unsigned short int >::print() { std::cout << "is integral" << std::endl; }
template<> void Value< unsigned       int >::print() { std::cout << "is integral" << std::endl; }
template<> void Value< unsigned  long int >::print() { std::cout << "is integral" << std::endl; }

template<> void Value<       float >::print() { std::cout << "is floating point" << std::endl; }
template<> void Value<      double >::print() { std::cout << "is floating point" << std::endl; }
template<> void Value< long double >::print() { std::cout << "is floating point" << std::endl; }

template< class T > void Value<T>::print() { std::cout << "unsupported type" << std::endl; }

int main( void )
{
    Value< float  >().print();
    Value< double >().print();
    Value< short  >().print();
    Value<   char >().print();
}
Run Code Online (Sandbox Code Playgroud)

输出:

is floating point
is floating point
is integral
unsupported type
Run Code Online (Sandbox Code Playgroud)

我想改变这一点以减少代码重复,特别是因为代码体比简单的std::cout. 为了说明我想要的方向,想到的最简单的想法是使用宏:

#define TMP(T) \
template<> void Value<T>::print() { std::cout << "is integral" << std::endl; }
TMP(          short int )
TMP(                int )
TMP(           long int )
TMP( unsigned short int )
TMP( unsigned       int )
TMP( unsigned  long int )
#undef TMP
#define TMP(T) \
template<> void Value<T>::print() { std::cout << "is floating point" << std::endl; }
TMP(       float )
TMP(      double )
TMP( long double )
#undef TMP
Run Code Online (Sandbox Code Playgroud)

但我想使用 C++11 模板魔法让它工作。我已经尝试使用std::enable_if,但我无法让它工作。比如这个

template< class T >
void Value<
    typename std::enable_if< std::is_integral<T>::value, T >::type
>::print( void )
{
    std::cout << "is integral" << std::endl;;
}
Run Code Online (Sandbox Code Playgroud)

给我

test.cpp:26:24: error: invalid use of incomplete type ‘struct Value<typename std::enable_if<std::is_integral<_Tp>::value, T>::type>’
 >::type >::print( void )
                        ^
test.cpp:14:8: error: declaration of ‘struct Value<typename std::enable_if<std::is_integral<_Tp>::value, T>::type>’
 struct Value
Run Code Online (Sandbox Code Playgroud)

std::enable_if在返回类型上使用:

template< class T >
typename std::enable_if< std::is_integral<T>::value, void >::type
Value<T>::print( void )
{
    std::cout << "is integral" << std::endl;;
}
Run Code Online (Sandbox Code Playgroud)

给我:

test.cpp:41:1: error: prototype for ‘typename std::enable_if<std::is_integral<_Tp>::value, void>::type Value<T>::print()’ does not match any in class ‘Value<T>’
 Value<T>::print( void )
 ^
test.cpp:16:17: error: candidate is: static void Value<T>::print()
     static void print( void );
Run Code Online (Sandbox Code Playgroud)

当然已经有很多类似的问题了:

但它们通常是关于简单的函数,而不是模板类的方法。此外,他们通常不会像我想要的那样严格分开声明和定义。

这个问题听起来非常相似,但它专门针对结构/类模板参数而不是另一个模板参数的方法。

由于上述错误,我似乎无法将答案应用于我的特定问题。此外,我不想专门化整个类,因为类本身共享许多对于所有类型 T 都相同的方法。我不想将一个复制粘贴代码换成另一个。

解释为什么会出现两条错误消息的奖励。我违反了什么规则。对我来说,似乎...::type根本没有用Tor代替void

Jar*_*d42 2

要允许您的结构使用 SFINAE,您必须添加额外的参数:

template<class T, typename AlwaysVoid = void>
struct Value;
Run Code Online (Sandbox Code Playgroud)

进而

template<class T>
struct Value<T, std::enable_if_t<std::is_integral<T>::value>>
{
    void print()
    {
        std::cout << "is integral" << std::endl;;
    }
};
Run Code Online (Sandbox Code Playgroud)