为类模板的单个成员定义专用化

define a specialization for a single member of a class template

本文关键字:成员 定义 专用 单个      更新时间:2023-10-16

我有一个包含许多成员函数的模板类(或者它是一个类模板?(。我有所有这些的定义。我想覆盖其中一个定义,对于 T 的特定值。我希望我不必为 T 的这个特定值提供所有成员函数的定义,因为它们都与泛型 T 的定义相同。

我已经尝试了如下所示的方法,但是我收到链接器错误" ...找到一个或多个乘法定义的符号">

是否使用了错误的语法,或者我正在做一些C++根本不允许的事情。

template <typename T>
struct A
{
    void a(T);
    void b(T);
    ...
    void z(T);
};
void A<int>::a(int)
{
    // do something special for this particular template parameter
}
template <typename T>
void A<T>::a(T){}
template <typename T>
void A<T>::b(T){}
...
template <typename T>
void A<T>::z(T){}

具体来说,这里有一些导致相同问题的真实代码:

template<typename T>
struct A
{ 
    void f(T);
};
template<> // same linker error with or without this line
void A<int>::f(int)
{
    // something special
}
template<typename T>
void A<T>::f(T)
{
}

你几乎是对的,你只是缺少template<>来表明明确的专业化:

template<>
void A<int>::a(int)
{
}

编辑:下面的答案正确地指出,如果要在标头中包含此实现,则应使用inline说明符。或者,您可以选择将实现移动到源文件,在这种情况下,您仍应在头文件中声明显式专用化。换句话说,它遵循常规函数定义规则。

template<> void A<int>::f(int)不再是

模板。所以不再inline.

你必须在 cpp 中实现它(并在标头中声明它(

或添加inline以避免有多个定义(因此在标题中定义(。

template<> inline void A<int>::f(int)
{
    // something special
}

感谢上面的回复者。我的问题本质上是我缺少内联关键字。这是有效的(释义(

 // in header file:
template <typename T>
struct A
{
    void a(T);
    void b(T);
    ...
    void z(T);
};
template <typename T>
void A<T>::a(T){}
template <typename T>
void A<T>::b(T){}
...
template <typename T>
void A<T>::z(T){}
// in .cpp file:
template <typename T>
inline void A<int>::a(int)
{
    // do something special for this particular template parameter
}

我希望我不必为 T 的这个特定值提供所有成员函数的定义,因为它们都与泛型 T 的定义相同。

如果可以使用 C++11,可能的解决方案是 SFINAE 启用/禁用通用或int特定的a()版本。

类似的东西

template <typename T>
struct A
 {
   template <typename U = T>
   typename std::enable_if<false == std::is_same<int, U>{}>::type a(T)
    { std::cout << "generic version" << std::endl; }
   template <typename U = T>
   typename std::enable_if<true == std::is_same<int, U>{}>::type a(T)
    { std::cout << "integer version" << std::endl; }
   void b(T) {}
   void z(T) {}
 };

为了避免可以以这种方式使用a()方法,请执行以下操作

A<float>{}.a<int>();

可以修改std::enable_if测试以检查TU是否相同

   template <typename U = T>
   typename std::enable_if<(false == std::is_same<int, U>{})
                        && (true == std::is_same<T, U>{})>::type a(T)
    { std::cout << "generic version" << std::endl; }
   template <typename U = T>
   typename std::enable_if<(true == std::is_same<int, U>{})
                        && (true == std::is_same<T, U>{})>::type a(T)
    { std::cout << "integer version" << std::endl; }

如果需要 C++98 解决方案,可以模拟std::is_same并按如下方式std::enable_if

template <typename, typename>
struct isSame
 { static const bool value = false; };
template <typename T>
struct isSame<T, T>
 { static const bool value = true; };
template <bool, typename>
struct enableIf
 { };
template <typename T>
struct enableIf<true, T>
 { typedef T type; };

你的A struct可以写

template <typename T>
struct A
 {
   template <typename U>
   typename enableIf<(false == isSame<int, U>::value)
                  && (true == isSame<T, U>::value), void>::type a(U)
    { std::cout << "generic version" << std::endl; }
   template <typename U>
   typename enableIf<(true == isSame<int, U>::value)
                  && (true == isSame<T, U>::value), void>::type a(U)
    { std::cout << "integer version" << std::endl; }
   void b(T) {}
   void z(T) {}
 };

另一种可能的 C++11 解决方案,不使用 SFINAE,而是使用几个辅助方法,是"标签调度"一个

template <typename T>
struct A
 {
   void a_helper (T, std::true_type const &)
    { std::cout << "integer version" << std::endl; }
   void a_helper (T, std::false_type const &)
    { std::cout << "generic version" << std::endl; }
   void a (T t)
    { a_helper(t, std::is_same<T, int>{}); }
   void b(T) {}
   void z(T) {}
 };