混合模板函数重载和继承

时间:2010-12-06 22:44:19

标签: c++ templates inheritance

以下代码打印:

generic
overload

但我想要的是在两种情况下都调用了重载或专门化,而不是通用的。我不是试图将重载与模板专业化混合在一起,因为它们没有像我预期的那样工作。是否有任何模板魔法来实现这一目标?

#include <iostream>

class Interface {};
class Impl: public Interface {};

class Bar
{
public:
    template<typename T> void foo(T& t) {
        std::cout << "generic\n";
    }
    void foo(Interface& t) {
        std::cout << "overload\n";
    }
};
template<> void Bar::foo<Interface>(Interface& t) {
    std::cout << "specialization\n";
}

int main() {
    Bar bar;
    Impl impl;
    Interface& interface = impl;
    bar.foo(impl);
    bar.foo(interface);
    return 0;
}

3 个答案:

答案 0 :(得分:5)

使用type_traits测试参数是否来自Interface的两种方法。

#include <boost/type_traits.hpp>

class Interface {};
class Impl: public Interface {};

class Bar
{
    template <class T> void foo_impl(T& value, boost::false_type)
    {
        std::cout << "generic\n";
    }
    void foo_impl(Interface& value, boost::true_type)
    {
        std::cout << "Interface\n";
    }
public:
    template<typename T> void foo(T& t) {
        foo_impl(t, boost::is_base_of<Interface, T>());
    }

};

如果满足条件,则禁用模板,只留下非模板作为候选模板。

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>

class Interface {};
class Impl: public Interface {};

class Bar
{
public:
    template<typename T>
    typename boost::disable_if<boost::is_base_of<Interface, T>, void>::type foo(T& t)
    {
        std::cout << "generic\n";
    }

    void foo(Interface&)
    {
        std::cout << "Interface\n";
    }
};

答案 1 :(得分:2)

为了使用专用函数,编译器需要进行从&Impl&Interface的参数转换。当它在寻找函数签名匹配时,完全匹配优先于需要转换的匹配。由于通用foo<T>是完全匹配,因此它会超过重载和专用函数。

答案 2 :(得分:0)

模板定义允许创建函数:

void Bar::foo<Impl>(Impl& t)

这是一个比你定义的Interface&参数更好的匹配。

你必须使超类函数更好地匹配,可能是这样的:

class Bar
{
    struct fallback { fallback(int) {} };
    template<typename T> void foo(T& t, fallback) {
        std::cout << "generic\n";
    }
    void foo(Interface& t, int) {
        std::cout << "overload\n";
    }
public:
    template<typename T> void foo(T& t) {
        foo(t, 0);
    }
};

似乎没有实际工作,请参阅http://ideone.com/IpBAv

所以你需要在泛型版本中进行类型测试,寻找Interface的子类。