从模板化类虚拟函数

时间:2018-06-30 21:52:53

标签: c++ templates template-specialization

我试图从类的重写虚拟函数中调用模板化函数。不幸的是,我似乎只能称之为默认实现。

#include <iostream>
#include <string>
#include <typeinfo>
#include <memory>

template<typename T1,
         typename T2>
class B;

template<typename T1,
         typename T2>
void bar(B<T1, T2> &b)
{
    std::cout << "T1 = " << typeid(T1).name() << std::endl;
    std::cout << "T2 = " << typeid(T2).name() << std::endl;
    std::cout << "Default template" << std::endl;    
}

template<typename T2>
void bar(B<int, T2> &b)
{
    std::cout << "Specialized template" << std::endl;    
}

template<typename T1, typename T2>
void foobar(T1 t1, T2 t2)
{
    std::cout << "Default template [foobar]" << std::endl;
}

template<typename T2>
void foobar(int t1, T2 t2)
{
    std::cout << "Specialized template [foobar]" << std::endl;
}

class A 
{
public:
    A() {}
    ~A() {}

    virtual void foo() = 0;
};

template<typename T1,
         typename T2>
class B : public A 
{
public:
    B() {}
    ~B() {}

    void foo() override
    {
        std::cout << "T1 = " << typeid(T1).name() << std::endl;
        std::cout << "T2 = " << typeid(T2).name() << std::endl;
        bar<T1, T2>(*this);
    }
};

int main()
{
    auto a = new B<int, char>();
    a->foo();

    bar<int, char>(*a);

    int i = 0;
    char b = 'b';
    foobar(i, b);
    foobar(b, b);

    return 0;
}

输出为(请参阅:here

T1 = i
T2 = c
T1 = i
T2 = c
Default template
T1 = i
T2 = c
Default template
Specialized template [foobar]
Default template [foobar]

显然,覆盖的foobar函数可以正常工作,但是,对于bar函数,从不调用专用版本。控制台中的输出显示,第一个模板参数显然是int,因此应调用覆盖的bar函数。

我感觉这与虚函数foo与类模板[1]不兼容有关。原则上,我想生成B类的不同版本,这些版本将覆盖虚拟foo函数,并要求对bar进行适当的特殊化(取决于类模板参数)。

我知道我可以只对B类进行部分专业化,但是这会导致很多重复的代码和其他复杂的设计。 (我也知道,通过模板化继承可以缓解其中的某些问题。)

我主要是想知道为什么尽管模板参数显然正确,却没有调用正确版本的bar。我不仅想提出重新设计的建议,还想知道为什么会有冲突。

1 个答案:

答案 0 :(得分:2)

这里的问题是bar实际上是两个单独的模板函数重载,第一个具有优先级。要为功能模板定义部分专业化,您可以对代理模板类使用技巧来完成所有工作:

template<typename T1, typename T2> class
bar_impl
{
    public: static void
    Do(B<T1, T2> &b)
    {
        std::cout << "T1 = " << typeid(T1).name() << std::endl;
        std::cout << "T2 = " << typeid(T2).name() << std::endl;
        std::cout << "Default template" << std::endl;    
    }
};

template<typename T2> class
bar_impl<int, T2>
{
    public: static void
    Do(B<int, T2> &b)
    {
        std::cout << "Specialized template" << std::endl;   
    }
};

template<typename T1, typename T2> void
bar(B<T1, T2> &b)
{
    return bar_impl<T1, T2>::Do(b);
}

online compiler