Search code examples
c++templatespartial-specialization

Avoiding duplication of function definitions in template specializations


The class Widget has some functions that apply for all parameter types (common functions) and other functions that need to be specialized for given types (the uncommon functions).

g++ insists that the specialization for Widget should also define common_fn() and not just uncommon_fn(), but that defeats the purpose of using specialization in the first place. How can one avoid repeating common_fn()?

#include <cassert>

template<typename Type> struct Widget
{
    Widget() {}
    char common_fn() { return 'a'; }
    int uncommon_fn() { return 1; }
};

template<> struct Widget<char>
{
    Widget() {}
    int uncommon_fn() { return 2; }
};

int main()
{
    Widget<char> WidgetChar;
    assert( WidgetChar.common_fn() == 'a' ); // Error
    assert( WidgetChar.uncommon_fn() == 2 );
}

begin-edit

to Alf:

I am unable to use

template<> int Widget<char>::uncommon_fn() { return 2; }

because some of the uncommon functions need to return a trait type (and so it was excessive to simplify by making the actual type primitive).

Or is there in fact a way to make the compiler recognize typename Foo::Bar when writing

struct Foo { typedef FooBar Bar; };
template<> typename Foo::Bar Widget<Foo>::uncommon_fn() { return ....; }

?

end-edit

begin-edit2

to iammilind:

That's interesting, but I am unable to use derivation from Widget (or the possibly clearer solution of refactoring the common parts into a parent class GeneralWidget) for the same reason. The common parts are not entirely common. Their declarations and their definitions look the same, but because they use traits they are at the end quite different.

end-edit2


Solution

  • #include <assert.h>
    
    template<typename Type> struct Widget
    {
        Widget() {}
        char common_fn() { return 'a'; }
        int uncommon_fn() { return 1; }
    };
    
    template<>
    int Widget<char>::uncommon_fn() { return 2; }
    
    int main()
    {
        Widget<char> WidgetChar;
        assert( WidgetChar.common_fn() == 'a' ); // OK
        assert( WidgetChar.uncommon_fn() == 2 );
    }