3

I have the following code (very simplified for the sake of clarity):

class Base
{
    virtual int DoStuff(int arg) = 0;
};

template <typename T>
class Derived : public Base
{
    int DoStuff(int arg) override
    {
         // do some stuff
         return 0;
    }
};

This works great. Now I want to implement a special (vectorized) implementation of DoStuff. And I need the implementation to be specific based on the type T that Derived has, something like this:

class Base
{
    virtual int DoStuff(int arg) = 0;
    virtual int DoStuffVectorized(int arg) = 0;
};

template <typename T>
class Derived : public Base
{
    int DoStuff(int arg) override
    {
         // do some stuff
         return 0;
    }

    int DoStuffVectorized<char>(int arg) override
    {
         // do some stuff for T == char
         return 0;
    }

    int DoStuffVectorized<int>(int arg) override
    {
         // do some stuff for T == int
         return 0;
    }
};

However i'm unable to make this work.

EDIT: I get the following error message: error C2143: syntax error: missing ';' before '<' on the line int DoStuffVectorized<char>(int arg) override.

When i change it to: template<char> int DoStuffVectorized(int arg) override i get: error C2898: ...': member function templates cannot be virtual

Any advice on how to achieve something like this? The reason i need it is that i have a std::vector that stores data of various types (by using Derived<>). This way i can use the same simple code regardless of the type being stored and i want this to be true even when using the special vectorized implementation of DoStuff that is sadly type specific.

PeterK
  • 6,287
  • 5
  • 50
  • 86

2 Answers2

3

You have to specialize template member functions outside of the class:

#include <iostream>

class Base
{
    public:
    virtual int DoStuffVectorized(int arg) = 0;
};

template <typename T>
class Derived : public Base
{
    public:
    int DoStuffVectorized(int arg) override;
};

template <>
int Derived<char>::DoStuffVectorized(int arg)
{
     std::cout <<  "T == char\n";
     return 0;
}

template <>
int Derived<int>::DoStuffVectorized(int arg)
{
     std::cout <<  "T == int\n";
     return 0;
}

int main(){
    Derived<char> c;
    Derived<int> i;
    Base* b[] = { &c, &i };
    for(auto* x : b)
        x->DoStuffVectorized(0);
    // undefined reference to `Derived<double>::DoStuffVectorized(int)'
    // Derived<double> d;
}

If you want to capture unintended instantiations at compile time:

#include <type_traits>

// A std::false_type (useful in a static_assert)
template <typename T>
struct static_false : std::false_type
{};

template <typename T>
int Derived<T>::DoStuffVectorized(int arg)
{
    static_assert(static_false<T>::value, "Neither 'char' or 'int'");
    return 0;
}
  • don't you think we should have one mone generic overload for DoStuffVectorized otherwise something like Derived f will not work – PapaDiHatti May 28 '16 at 09:46
  • Thank you, this is exactly what i want! – PeterK May 28 '16 at 09:52
  • But why to complicate stuff with std::false_type why not directly use static_assert(false, "Neither 'char' or 'int'"); – PapaDiHatti May 28 '16 at 10:03
  • @Kapil The compiler will see a not (template) deduced 'false', which will always cause an assertion (even for 'char' and 'int') –  May 28 '16 at 10:16
  • Ok i can see there will be error if we use false directly but could not understand why compiler is going to this generic function even for char and int – PapaDiHatti May 28 '16 at 10:31
  • Got the answer from this link http://stackoverflow.com/questions/14637356/static-assert-fails-compilation-even-though-template-function-is-called-nowhere – PapaDiHatti May 28 '16 at 10:36
2

DoStuffVectorized<char> is not correct syntax, DoStuffVectorized isn't template itself.

See template specialization:

template <typename T>
class Derived : public Base
{
    int DoStuff(int arg) override
    {
         // do some stuff
         return 0;
    }
    int DoStuffVectorized(int arg) override
    {
         // do some stuff (primary template)
         return 0;
    }
};

template <>
int Derived<int>::DoStuffVectorized(int) {
     // do some stuff for T == char
     return 0;
}

template <>
int Derived<char>::DoStuffVectorized(int) {
     // do some stuff for T == char
     return 0;
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405