2

In the curiously recurring template pattern, we write

template <class Derived>
class Base {
};

class Derived : public Base<Derived> {
};

What would be a good way to make the code robust another copy-paste omissions, so that the following snippet throws a compile-time error:

class AnotherDerived : public Base<Derived> {
};

I'm using Visual C++ 2013.

Walter
  • 44,150
  • 20
  • 113
  • 196
krlmlr
  • 25,056
  • 14
  • 120
  • 217
  • 1
    Give `Base` a private dtor and then make `Derived` a friend? – T.C. Feb 16 '15 at 19:36
  • Maybe the constructor Base(Derived&) {} - but that is close to being paranoid. –  Feb 16 '15 at 19:38
  • @DieterLücking: Thought about that, but this messes up the interface, too... – krlmlr Feb 16 '15 at 19:49
  • @T.C.: Nice idea -- but is this possible without giving `Derived` access to other private members of `Base`? – krlmlr Feb 16 '15 at 19:50
  • @krlmlr: You can add another inheritance layer to hold the members that need to remain private. Using composition should also be possible. (Remember friendship is not transitive) – Ben Voigt Feb 16 '15 at 19:52
  • @BenVoigt: Thanks a lot, a second inheritance layer did the trick for me. – krlmlr Feb 16 '15 at 20:08
  • The 'duplicate' answer is pre-C++11 and hence not appropriate. I vote for re-opening. Moreorver, the answers given are not fully satisfactory. – Walter Nov 19 '15 at 14:39
  • @Walter: Can you suggest a better solution using C++11 features? – krlmlr Nov 20 '15 at 11:50
  • @krlmlr No, but perhaps somebody else can. – Walter Nov 20 '15 at 22:32

2 Answers2

4

Make Base's destructor private, and then make Derived a friend of Base<Derived>:

template <class Derived>
class Base {
    private: ~Base() = default;
    friend Derived;
};

class Derived : public Base<Derived> {
};

This does not actually make doing

class AnotherDerived : public Base<Derived> {
};

illegal, but any attempt to actually construct an AnotherDerived will fail.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Thanks, this works for me -- I now have a class `BaseImp` from which `Base` inherits in order to avoid exposing private members to the pseudo-friend. – krlmlr Feb 16 '15 at 20:10
1

You can static_assert that the argument derives from Base<Argument>, but that's as far as you can go.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 1
    Where would you do that? Inside the base class as a member-declaration, that information might not be available (yet) -- in fact, the Standard requires the second argument of `is_base_of` is a complete type. Inside a member function, an instantiation of that member function might be required to actually perform the check. – dyp Feb 16 '15 at 19:48
  • @dyp: Would the check always be done if performed in the constructor of `Base`? – krlmlr Feb 16 '15 at 20:11
  • I'm not too familiar with static assertions -- could you please give an example? – krlmlr Feb 16 '15 at 20:11
  • @krlmlr As far as I know, a `static_assert` inside a constructor of `Base` is only checked if that constructor is instantiated (e.g. if it is called). Although the error message might be better, I think the requirements for the `static_assert` check to be performed are higher than the check T.C. proposed. – dyp Feb 16 '15 at 20:21