Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call "base" template function from C++ template specialization that "overrides" it?

Tags:

c++

templates

The question:

Is there a way to call the "base" template function from a specialized template function in C++, the way a child class can access the parent's versions of virtual methods when overriding them? (NOTE: I suspect the answer is "no" but would love to be wrong)

The context:

I often find myself specializing a template function only because a special case needs extra pre- or post-processing, not because the "guts" of the code have changed.

To give a contrived example:

With inheritance, you can do the following:

struct base { 
    virtual void go() { printf("%p", this); }
};
struct foo : base { 
    virtual void go() { printf("this foo lives at "); base::go(); } 
};

... and calling foo::go() will print "this foo lives at <address>"

With templates, though:

template <typename T>
void go(T const &t) { printf("%p\n", &t); }

template <>
void go(foo const &f) { 
    printf("this foo lives at "); 
    ??? how to access "base" template ??? 
}

You can work around the problem in an ugly way by factoring out a mess of little helper functions and specializing them instead of the function you actually care about:

template <typename T>
void _go_pre(T const &t) { /* do nothing */ }

template <typename T>
void _go_post(T const &t) { /* do nothing */ }

template <typename T>
void go(T const &t) { 
    _go_pre(t); /* just in case */
    printf("%p\n", &t); 
    _go_post(t); 
}

template<>
void _go_pre(foo const &t) { printf("this foo lives at "); }

... but that clutters the code significantly because now the "base" template needs to anticipate all the ways a "child" specialization might override it, and most types will use few, if any, of those hooks. The clutter becomes unreadable and unmaintainable pretty quickly, because the reason for these hooks is not known at the point where they are defined, and you have to test the different combinations of used/unused hooks.

All this is exactly like the problems you'd have with virtual method overrides in a world where a child class couldn't access original version provided by the parent class.

like image 934
Ryan Avatar asked Oct 22 '22 08:10

Ryan


1 Answers

It's not possible directly. However, you can do with fewer (and IMO less ugly) helpers like this:

template <typename T>
void base_go(T const &t) { printf("%p\n", &t); }

template <typename T>
void go(T const &t) { base_go(t); }

template<>
void go(foo const &t) { printf("this foo lives at "); base_go(t); }

As an alternative, you could put the base_ variants into a separate namespace instead of giving them modified names.

like image 157
Angew is no longer proud of SO Avatar answered Oct 24 '22 03:10

Angew is no longer proud of SO