6

If I have a template class

template<typename T>
class C {
public:
    void method1() { ... }
    void method2() { ... }
    std::string method3(T &t) {
        // ...
        std::string s = t.SerializeToString();
        // ...
        return s;
    }
    // ...
};

and I want to specialize it for T = std::string but only changing method3(T&) (keeping all other methods), or even better, only that part of method3, which for T = std::string would simply become std::string s = t;, with minimum impact on current code (less repetition of methods signatures, less subclassing), how would I do it?

EDIT: I'm developing in C++11

fferri
  • 18,285
  • 5
  • 46
  • 95

2 Answers2

6

You can use specialization like that (no need to specialize the whole class):

template<>
std::string C<string>::method3(string &t) {
    // ...
    std::string s = t;
    // ...
    return s;
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I posted a minimal example, but in reality I do need to specialise the whole class – fferri Oct 31 '17 at 12:39
  • 1
    @fferri: you title literally says **"specialize only (a part of) one method of a template class"**. – Vittorio Romeo Oct 31 '17 at 12:39
  • @Jarod42: are you suggesting to remove the template parameter for the class? Or I misunderstood your answer. – fferri Oct 31 '17 at 12:43
  • @fferri it's called a template function. – UKMonkey Oct 31 '17 at 12:46
  • 1
    @fferri: If you specialize the whole class, you have to rewrite `method1`/`method2` too. You can (fully) specialize only the given method. class is still template, method is not. – Jarod42 Oct 31 '17 at 12:57
5

If you only need to change s's initialization, you can use overloading:

std::string init(std::string& t)
{
    return t;
}

template <typename T>
std::string init(T& t)
{
    return t.SerializeToString();
}

template <typename T>    
std::string method3(T &t) {
    // ...
    std::string s = init(t);
    // ...
    return s;
}

In C++17, you can use if constexpr:

std::string method3(T &t) 
{
    if constexpr(std::is_same_v<T, std::string>)
    {
        std::string s = t;
        // ...
        return s;
    }
    else
    {
        std::string s = t.SerializeToString();
        // ...
        return s;
    }
}

In C++14, you can use static_if:

std::string method3(T &t) 
{
    static_if(std::is_same<T, std::string>{})
    .then([](auto& x)
    {
        std::string s = x;
        // ...
        return x;
    })
    .else_([](auto& x)
    {
        std::string s = x.SerializeToString();
        // ...
        return x;
    })(t);
}
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416