Using directive with member function templates

I want to get from a class that contains templated member functions. In the derived class, I want to add some more specializations for member functions. But how can I make the already defined methods from the parent class visible. Usually I should use using

, but I cannot find the correct syntax for templated methods. And how can I tell, I want to define more specialized methods in the derived class without overwriting the non-specialized method of the base class.

As we write 2017, all modern C ++ dialects are welcome.

#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"
}

      

+3


source to share


2 answers


Maybe not everything is caught in C ++ 17, when we manage to send the good old tag:

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

Output:



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

      

You saw that the operator using

successfully introduces wildcard names, but unlike its inheriting constructors, it doesn't actually create these member functions, which would force you to specialize Do

for A

, which is not what you want.

So instead, we define overloads for the types we want to specialize in A

and separately define overloads for the types we want to specialize in B

. We have to hide the A

Do

function in B

with our own, unfortunately, because the class A

cannot post to B overloads (but B

can post to the A

. Operator using

for DoHelp

, so it B

can see overloads A

).

tag

as you can see, just an empty template struct

. We use it as a way to distinguish between identical functions ( DoHelp

). Since we are not using a parameter, the optimizing compiler will not actually create the object, so we should not see any overhead. If we do this, it will only be 1 byte.

+1


source


When you write a Do method in class B, you are actually adding a new template member function that shadows A :: Do and does not add the specialization A :: Do. There is also no need to use "A :: Do"; statement.



-1


source







All Articles