2014-01-08 95 views
0

我想通过它的模板参数的类型特征来专门化模板类上的成员函数,但是我的前向声明显然是不正确的。有一个简单的解决方法吗?按类型专门化模板类成员函数

#include <type_traits> 

template <typename T> 
class TTest{ 
public: 
    T data; 

    // edited to comment this out, template<typename U> 
    bool operator !=(const TTest& other) const; 
}; 

template <typename T> 
typename std::enable_if<std::is_unsigned<T>::value, bool>::type 
TTest<T>::operator !=(const TTest<T>& other) const{ 
    return true; 
} 

template<typename T> 
bool TTest<T>::operator !=(const TTest<T>& other) const{ 
    return false; 
} 

int main(){ 
    TTest<size_t> t1; 
    TTest<int> t2; 
} 

锵告诉我:

templateTest.cpp:13:11: error: out-of-line definition of 'TTest::operator!=' 
    differs from the declaration in the return type 
TTest<T>::operator !=(const TTest<T>& other) const{ 
     ^
templateTest.cpp:8:8: note: previous declaration is here 
    bool operator !=(const TTest& other) const; 
    ^
1 error generated. 
+0

此代码没有意义。成员模板对模板参数具有* no *依赖性,所以没有什么特别的。 –

+0

你是否意识到'const TTest&other'是指你rmember模板中的'const TTest &other'? –

+0

你不能部分地专门化一个函数模板。如果你想要一个无符号T和非无符号T的版本,那么你需要重载+ SFINAE或部分专门化整个类模板。 – dyp

回答

4

看起来好像整个012bshebang是函数签名的一部分(或者我真的不明白错误)。我可以得到代码编译和行为,只要你想,如果我将其更改为

template <typename T> 
class TTest{ 
public: 
    T data; 

    template<typename U> 
    typename std::enable_if<std::is_unsigned<U>::value, bool>::type 
    operator !=(const TTest<U>& other) const; 

    template<typename U> 
    typename std::enable_if<not std::is_unsigned<U>::value, bool>::type 
    operator !=(const TTest<U>& other) const; 
}; 

template <typename T> 
template <typename U> 
typename std::enable_if<std::is_unsigned<U>::value, bool>::type 
TTest<T>::operator !=(const TTest<U>&) const{ 
    return true; 
} 

template <typename T> 
template <typename U> 
typename std::enable_if<not std::is_unsigned<U>::value, bool>::type 
TTest<T>::operator !=(const TTest<U>&) const{ 
    return false; 
} 

Live demo。当然,如果将这些运算符定义为内联,这会减少很多重复性。

更好的方法可能是根据T的特性分派到运营商逻辑的不同私有实现。这会从您的代码中删除所有SFINAE详细信息。

template <typename T> 
class TTest{ 
public: 
    T data; 

    bool operator!=(const TTest& other) const 
    { 
     return not_equal_to(other, typename std::is_unsigned<T>::type()); 
    } 

private: 
    bool not_equal_to(TTest const&, std::true_type) const 
    { 
     return true; 
    } 

    bool not_equal_to(TTest const&, std::false_type) const 
    { 
     return false; 
    } 
}; 

Live demo

+0

第一个答案似乎工作,但我有2个问题:如果我内联这些定义,我得到含糊/无法推断错误(取决于如果我使用。任何想法为什么?其次,我并不是真的想要比较不同类型的TTests,但这种方法似乎允许它。任何方式? –

+0

我没有[得到任何错误](http:// coliru .stacked-歪。com/a/0db61b7bcec2cfd5)与内联定义的gcc或clang。你无法摆脱'template ',因为SFINAE需要模板参数推导才能工作。为了确保不会比较不同类型,可以在定义中添加'static_assert(std :: is_same :: value,“”)''。无论如何,我建议你完全不使用'enable_if'并遵循第二种方法,除非有什么阻止你这样做。 – Praetorian

+0

哎呀,我错过了一些内嵌的内容,也在我的机器上工作,谢谢。你为什么喜欢第二种方法?模板噪音较少? –

1

你宣布你模板类的成员函数模板,您要专门为成员函数。这不会飞。而且,返回类型不同,尽管最终评估的是同样的事情。

我不知道你试图尝试什么,因为成员函数模板的U类型甚至没有被推导出来(你的意思是参数类型为TTest<U>?)。如果你想基于一个特点专门您的会员,我想你会要么需要牛逼超载操作或使用不同的方法(例如,委托执行的专门类模板):

#include <iostream> 
#include <type_traits> 

template <typename T> 
class TTest{ 
public: 
    T data; 

    template<typename U> 
    typename std::enable_if<!std::is_unsigned<U>::value, bool>::type 
    operator !=(const TTest<U>& other) const; 

    template<typename U> 
    typename std::enable_if<std::is_unsigned<U>::value, bool>::type 
    operator !=(const TTest<U>& other) const; 
}; 

template <typename T> 
template<typename U> 
typename std::enable_if<!std::is_unsigned<U>::value, bool>::type 
TTest<T>::operator !=(const TTest<U>& other) const { 
    return true; 
} 

template <typename T> 
template<typename U> 
typename std::enable_if<std::is_unsigned<U>::value, bool>::type 
TTest<T>::operator !=(const TTest<U>& other) const { 
    return false; 
} 

int main(){ 
    TTest<unsigned int> t1; 
    TTest<int> t2; 
    std::cout << std::boolalpha 
      << "t1 != t1: " << (t1 != t1) << '\n' 
      << "t1 != t2: " << (t1 != t2) << '\n' 
      << "t2 != t1: " << (t2 != t1) << '\n' 
      << "t2 != t2: " << (t2 != t2) << '\n'; 
} 
+0

在您的类声明中,他会完成模板。然后这是有道理的(并会工作)。在另一端的可读性.... – jyavenard

1

tag分派是干净的方法来做到这一点:

template <typename T> 
class TTest{ 
    bool not_equal(const ITest& other, std::true_type /* is unsigned */) const; 
    bool not_equal(const ITest& other, std::false_type /* is unsigned */) const; 
public: 
    T data; 

    bool operator !=(const TTest& other) const { 
    return not_equal(other, std::is_unsigned<T>()); 
    } 
}; 

现在简单地实现这两个TTest<T>::not_equal重载。只有实际调用给定T的那个将被编译通过基本解析。