专门的模板成员功能?

时间:2011-11-19 22:14:43

标签: c++ templates instantiation

我想在模板化类中为成员函数定义几个不同的函数定义。像这样:

template <typename T>
class MyClass
{
  void Foo();
  T val;

  //other functionality and data
};

  //handles all types
template <typename T>
void MyClass<T>::Foo()
{
  return val;
}

  //handles a special type in a different way
template <>
void MyClass<float>::Foo()
{
  return val + 5.0f;
}

我已经尝试过如上所述的实现,并为我尝试显式实例化的每个特殊类型获取链接器错误。链接器错误提到该函数之前已经定义过。也许我正在寻找错误的地方,但我找不到任何资源来帮助我找出这个问题:(

Q值。这可能吗?如果是这样,你如何做到这一点以及它为什么有效?

谢谢!

4 个答案:

答案 0 :(得分:3)

这是我经常使用的解决方法。如前所述,您必须专门化完整的模板。我们的想法是使你想要专门化某个结构的静态成员的方法(由于封装原因,它应该是嵌套的和私有的)。像这样:

template< typename T >
class MyClass {

    struct PerformFoo {
        static void doFoo () {
            std::cout << "Foo for general type" << std::endl;;
        }
    };

public:
    void Foo () {
        PerformFoo::doFoo();
    }
};

template<>
struct MyClass< float >::PerformFoo {
    static void doFoo () {
        std::cout << "Foo for float" << std::endl;;
    }
};

现在在你的主要代码

MyClass< int > myInt;
myInt.Foo();

MyClass< float > myFloat;
myFloat.Foo();

打印

Foo for general type
Foo for float
终端上的

。顺便说一句:这不涉及现代编译器的任何性能损失。希望这会对你有所帮助。

答案 1 :(得分:1)

通过将专用成员函数定义为内联函数,您将摆脱链接错误,抱怨已在其他地方定义的专用成员函数。

//handles a special type in a different way
template <>
inline void
MyClass<float>::Foo()
{
  return val + 5.0f;
}

原因是专门的函数不再是函数模板,而是具体的函数。因此,在编译包含此头文件的源文件时,它将被编译多次,这就是为什么你得到“已经定义”的错误。

另一种解决方案是将专用函数的实现移出头文件并将其放入源文件中,同时在头文件中声明专用函数。请注意,专用成员函数的声明必须保持在类定义之外:

/// Declare the specialized function in the header file but outside the
/// class definition. 
template <> void MyClass<float>::Foo()

/// Define the specialized function in .cpp file:
template <>
void
MyClass<float>::Foo()
{
  return val + 5.0f;
}

答案 2 :(得分:0)

  

我已尝试按上述方法实现此操作,并为我尝试显式实例化的每种特殊类型获取链接器错误。

这是什么意思?如果您明确地专门化了模板,则无法为相同的模板参数显式实例化它。显式特化的整个目的是阻止它的实例化(这是生成的特化)有利于您的显式特化

所以你的描述对我来说没有意义。请记住,如果要隐式实例化它们,则需要将模板的定义和类模板的成员函数放在标题中,而不是放在.cpp文件中。并且需要向使用其模板及其参数的每个人声明显式特化。

// put this specialization into the header, for everyone to see
template <> void MyClass<float>::Foo();

答案 3 :(得分:-1)

这是不可能的。当您专门化模板时,您必须专门化整个模板,在这种情况下,这意味着整个类。

您可以在模板类中使foo成为模板函数。它与您要求的不完全相同,但它可能满足您的需求。

<强>更新

template<typename T> class Foo {
public:
    template<typename R> void foo() {printf("This is foo\n");}
    template<> void foo<float>() {printf("This is foo<float>\n");}
};

或者:

template<typename T> class Foo {
public:
    template<typename R> void foo() {printf("This is foo\n");}
    //template<> void foo<float>() {printf("This is foo<float>\n");}
};

template<> template<> void Foo<float>::foo<float>() {
    printf("This is foo<float>\n");
}

以及:

int main(int argc,char * argv[])
{
    Foo<int> iFoo;
    iFoo.foo<int>();

    Foo<float> fFoo;
    fFoo.foo<float>();

    return 0;
}

产生

This is foo
This is foo<float>

调用foo的语法有点尴尬。