2011-11-19 163 views
1

我想为模板类中的成员函数有几个不同的函数定义。事情是这样的:专用模板成员函数?

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; 
} 

我试图实现与上述这一点,并得到一个链接错误为每个特殊类型的我尝试显式实例。链接器错误提到该函数已经被定义过。也许我在错误的地方看,但我找不到任何资源来帮助我找出这个问题:(

问:这是可能的吗?如果是这样,你如何做到这一点,为什么它的工作?

谢谢!

+0

我刚刚粘贴您的定义在头文件中,这是我从两个不同的源文件包括在内;在两个源文件中,我为专门和非专用模板类的实例都调用了Foo()方法。一切正常,用g ++ - 4.4.3。你能否提供一些关于链接器错误和项目结构的更多细节? – misberner

+1

这应该工作;你的问题必须在别处。确保您熟悉常规模板机制以及标题和链接问题。 –

+1

[适用于我](https://ideone.com/IpHd0)。 –

回答

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 

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

+0

谢谢,这绝对解决了这个问题。所以这个原因起作用的原因是因为我需要在使用之前完全专注于该函数调用。通过使它成为我的类可以专门化的结构的静态成员,可以确保在调用之前该结构本身将专用化,对吗?再次感谢您的帮助。 – KiraBox

+0

对不起,延迟回答。我不知道这是否是'正确的'解释,因为我不是C++编译器实现方面的专家。我只知道这是有效的,而且这个技巧用于一个科学项目中,我正在努力研究:) – Sh4pe

-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的语法有点尴尬。

+0

我以为是一样的,但一个简单的实验(使用g ++ 4.4.3)刚刚证明我错了。 – misberner

0

我试着实现这个如上所述,并获得每个特殊类型的链接器错误,我尝试显式实例化。

这是什么意思?如果明确地专门化模板,则不能再为相同的模板参数显式实例化它。显式专业化的全部目的是防止它的实例化(这是一个生成的专业化)有利于你的明确的专业化

所以你的描述对我来说没有意义。请记住,如果要隐式实例化它们,则需要将头文件的模板和成员函数的定义放在头文件中,而不要放在.cpp文件中。而且需要向所有使用模板和参数的人声明明确的专业化。

// put this specialization into the header, for everyone to see 
template <> void MyClass<float>::Foo(); 
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; 
}