using指令与模板化成员函数

时间:2017-04-04 07:23:24

标签: c++ templates using

我想从包含模板化成员函数的类派生。在派生类中,我想为成员函数添加一些更多的特化。但是,如何使父类中已定义的方法可见。通常我必须使用using,但我找不到模板化方法的正确语法。我怎么说我想在派生类中定义更专业的方法而不覆盖基类的非专用方法。

在我们写2017年的时候,欢迎任何现代的c ++方言。

#include <iostream>

class MyType1{};
class MyType2{};

class A
{
    public:
        template <typename T>
            void Do() {std::cout << "Default" << std::endl; }
};

template<>
void A::Do<MyType1>() { std::cout << "For MyType1" << std::endl; }

class B : public A
{
    public:
       using A::Do; ??? how to do this for templated members?


        // how to make it possible to write more specializations without
        // defining a new "default" one?
        template <typename T>
            void Do() {std::cout << "Default of B" << std::endl; }
};

template<>
void B::Do<MyType2> (){ std::cout << "For MyType2" << std::endl; }

int main()
{
    A a;

    a.Do<int>();     // should give "Default"
    a.Do<MyType1>(); // should give "For MyType1"
    a.Do<MyType2>(); // should give "Default"
    std::cout << "-----------" << std::endl;

    B b;
    b.Do<int>();     // should give "Default"
    b.Do<MyType1>(); // should give "For MyType1"
    b.Do<MyType2>(); // should give "For MyType2"
}

2 个答案:

答案 0 :(得分:1)

当好的旧标签发送将帮助我们解决时,让我们不要全部陷入C ++ 17:

namespace detail{
   template<class...>
   struct tag{}; // for dispatch to overloads below
}

class A
{
public:
    template <typename T>
    void Do() {
        DoHelp(detail::tag<T>{});
    }
protected:
    template<class... U>
    void DoHelp(detail::tag<U...>)
    {
        std::cout << "Default" << std::endl;
    }

    void DoHelp(detail::tag<MyType1>)
    {
        std::cout << "For MyType1" << std::endl;
    }
};

class B : public A
{
public:
    template <typename T>
    void Do() {
        DoHelp(detail::tag<T>{});
    }
protected:
    using A::DoHelp;
    void DoHelp(detail::tag<MyType2>){
        std::cout << "For MyType2" << std::endl; 
    }      
};

Demo

输出:

Default
For MyType1
Default
-----------
Default
For MyType1
For MyType2

您已经看到using语句成功引入了模板化名称,但与继承构造函数不同,它实际上并不会创建这些成员函数,这会强制您为Do专门化A这不是你想要的。

因此,我们为A中我们想要专门化的类型定义重载,并为我们想要在B中专门化的类型单独定义重载。不幸的是,我们必须隐藏A Do B函数与我们自己的A函数,因为类B无法调度到B的重载(但A可以调度到using {1}}。DoHelp的{​​{1}}语句是B可以看到A的重载。)

如您所见,tag只是一个空模板struct。我们使用它来区分其他相同的函数(DoHelp)。因为我们不使用参数,优化编译器实际上不会构造对象,所以我们不应该看到任何开销。如果我们这样做,它将只有1个字节。

答案 1 :(得分:-1)

通过在B类中编写Do方法,您实际上是在添加一个新的模板成员函数,该函数隐藏A :: Do而不添加A :: Do特化。也没有必要使用A :: Do;&#34;言。