richardr
richardr

Reputation: 5182

How can one avoid duplicating class template specification for each member function?

If I have a template class specification like so,

template <typename T>
class MyClass {
public:
    void fun1();
    // ...
    void funN();
};

template <typename T>
void MyClass<T>::fun1() {
    // definition
}

// ...

template <typename T>
void MyClass<T>::funN() {
    // definition
}

If I change the class template to something else, say I add an extra parameter:

template <typename T, typename U>
class MyClass {
    // ...
};

Then I have to change each function definition (fun1, ..., funN) to agree with the class template specification:

template <typename T, typename U>
void MyClass<T,U>::fun1() { //... }

Are there any strategies for avoiding this? Could I use macros e.g.

#define DFLT_TEMPLATE template<typename T, typename U>
#define DFLT_CLASS  class<T,U>

DFLT_TEMPLATE
void DFLT_CLASS::fun1() { // ... }

Or is this considered bad practice?

Upvotes: 8

Views: 722

Answers (7)

sbi
sbi

Reputation: 224049

How many member functions do you have that this is an issue?

I think either they are small enough to be defined within the class template or the adaption of their algorithms to an additional template parameter would by far outweigh the replacement of those function headers.

Also, your editor ought to do this for you in no time anyway.

Upvotes: 2

Steve Jessop
Steve Jessop

Reputation: 279245

As far as possible, put the function definitions in the class template definition. It's a template, so unless you're using Comeau compiler, it's not as if they're going to be off in a different TU.

If the functions use something which is defined in between the class definition and the function definition, then you can play tricks to make that thing dependent on a template parameter even when "really" it isn't. For example:

template <typename T>
struct Foo {
    void usebar();
};

struct Bar {
    int a; 
    Foo<int> circularity; // circular dependency between Foo and Bar
    Bar() : a(3) {}
};

template <typename T> void Foo<T>::usebar() {
    Bar b;
    std::cout << b.a << "\n";
}

Becomes:

// we only have to write "same" once
template <typename T, typename U>
struct same {
    typedef U type;
};

struct Bar;

template <typename T>
struct Foo {
    void usebar() {
        typename same<T,Bar>::type b;
        std::cout << b.a << "\n";
    }
};

struct Bar {
    int a; 
    Foo<int> circularity; // circularity gone
    Bar() : a(3) {} 
};

Or actually in this case just:

struct Bar;

template <typename T, typename B = Bar>
struct Foo {
    void usebar() {
        B b;
        std::cout << b.a << "\n";
    }
};

struct Bar {
    int a;
    Foo<int> circularity;
    Bar() : a(3) {}
};

All cases support the following code:

int main() {
    Foo<int> f;
    f.usebar();
}

Upvotes: 1

log0
log0

Reputation: 10917

There are probably some (more or less bad) workarounds, but you definitely point out a " missing" feature of C++: class namespace extension.
Some people already proposed to extend C++ in this way:
http://www.lrde.epita.fr/dload//20080709-Seminar/ordy-classnamespaces.pdf

namespace foo
{
  class bar
  {
    typedef int baz_t;
    baz_t my_method ();
  };
}
namespace class foo::bar
{
  baz_t my_method ()
  {
  // ...
  }
}

--
Using a macro is not a good idea (usual things about macros ....). I would prefer, at worst, write function members definitions inline in this case, or even better use an editor than can help you easily update your class definition.

Macros are bad because they let you write code editing functions where you are supposed to write programs. If you want to edit code, use your editor (sed, M-x replace-*, Find&Replace ...)

Upvotes: 0

Charles Salvia
Charles Salvia

Reputation: 53289

To me, the benefits of using a macro here are far overshadowed by the drawbacks. Yes, if you use a macro then if you ever need to add an additional template parameter, you'll only need to make a single modification. But anyone else reading your code is probably going to vomit.

I mean, are you going to do this for every template you have? Your code will become infested with ugly macros.

Upvotes: 6

peoro
peoro

Reputation: 26060

Inheritation is better than macro.

If you want to change only a few functions and variables, make the specialized class inherit a common class that provides common functions/variables.

Upvotes: 1

Moo-Juice
Moo-Juice

Reputation: 38825

I would consider this approach bad practice. What you are complaining about is that you have changed your design (you need an extra template parameter) and now want a kludge to save on typing?

Introducing macros is going to decrease the readability of your code. Preprocessor definitions certainly have their place, but personally I'd never advocate one on the grounds that I can't be bothered to change my functions.

Upvotes: 0

pboulanger
pboulanger

Reputation: 31

yes you could but don't forget to use "#undef DFLT_TEMPLATE" and "#undef DFLT_CLASS" at the end of file to avoid compiler warnings if your project have several templates with same macros definitions

Upvotes: 2

Related Questions