Assume that one has two base classes Base1 and Base2 for which CRTP pattern is desired.
template <typename TDerived>
class Base1 {
};
template <typename TDerived>
class Base2 {
};
Now I would like to define a Derived class such that it can be "parametrized" with a base one.
What would be the proper way to define it in C++ (C++17 if that matters)?
Below is a pseudo-C++ code
template <template <typename> class TBase>
class Derived : public TBase<Derived<TBase>> {}; // Recursion problem here
In reality such a derived class is an extension that is applicable to any base class.
From your comment:
The problem I think still exists.
Consider your own pseudo-code when fed to a compiler (and some addition):
template <typename TDerived>
struct Base1 {
auto get() const -> int {
return static_cast<TDerived const*>(this)->a;
}
};
template <typename TDerived>
struct Base2 {
auto get() const -> int {
return static_cast<TDerived const*>(this)->b;
}
};
template <template<typename> typename TBase>
struct Derived : TBase<Derived<TBase>> {
int a;
int b;
};
auto main() -> int {
auto b = Derived<Base1>{};
b.a = 1;
b.b = 2;
return b.get();
}
Live example
As you can see, that pattern is no problem for the compiler.
Now I would like to define a Derived class such that it can be "parametrized" with a base one. What would be the proper way to define it in C++ (C++17 if that matters)?
The way you posted it in the question is the right way, and works all the way to C++98.
You seem to state that there's a recursion problem here, but there is not.
You have a template class Derived with a template template parameter Base1. The compiler now "knows" that this type Derived<Base1>. It is incomplete though, until the } is reached.
Then the compiler sees the base, which is TBase<something>, which is Base1 with some template parameter. Base1 need to be instantiated. The something is Derived<Base1>, which is an incomplete type.
The compiler then instantiate Base1 with Derived<Base1>. During that process, you cannot use Derived<Base1> in a way that it would require it to be complete.
Now that the base is instantiated and a complete type, the compiler finishes to instantiate Derived<Base1>, now complete.
There is no recursion here.
Related
Why the *this of the derived<T> class is still of base<T> type?
I thought the typename X would take care of that.
If this looks ugly, what is a better way?
Failed Attempt:
template <typename T>
class Derived;
template <typename T, typename X>
class Base{
public:
T val;
X f(void){
return *this;
}
};
template <typename T>
class Derived: public Base<T, Derived<T> >{
};
int main(void){
Derived<int> B;
Derived<int> C = B.f();
}
Error:
test4.cpp(9): error: no suitable user-defined conversion from "Base<int, Derived<int>>" to "Derived<int>" exists
return *this;
^
detected during instantiation of "X Base<T, X>::f() [with T=int, X=Derived<int>]" at line 20
compilation aborted for test4.cpp (code 2)
You may do the downcast with:
X f(){ return static_cast<X&>(*this);}
When the compiler looks at class Base<int, Derived<int>> it has no reason to believe that there is actually a Derived<int> that inherited from it. One could do class Other : public Base<T, Derived<T>>{} and the conversion from class Base<int, Derived<int>> to Derived<int> would be incorrect, so an automatic conversion is not allowed.
If you make a rule that says that the second template parameter must be the derived type that inherits that base (which class Other violates) you can bypass the type system with a cast, but make sure the rule is not violated.
You have
X f(void){
return *this;
}
In this function, type of *this is still the base class type. There is no automatic conversion from the base type to X.
I am unable to suggest a clean solution since X can be anything at that point, not necessarily Derived<T>.
I can use:
template <typename T>
class Derived2 : public Base<T, double>
{
};
How's the base class supposed to deal with that?
The approach used in f() seems to be a design flaw.
Update
If Derived is guaranteed to have the form
template <typename T>
class Derived : public Base<T, Derived<T>>
{
};
Then, you can use:
X& f(void){
return static_cast<X&>(*this);
}
Please note that I changed the return type from X to X&. It avoids the cost of making a copy every time you call the function.
First of all, I would modify Base so that it accepts only one template parameter.
This way, it matches exactly the common form shown for the CRTP idiom.
Actually, it seems to me that there is no reason to use both T and Derived<T> as a template parameter in this case, for the latter already contains the former and T, Derived<T> is the pattern to which you want to adhere:
template<typename>
class Base;
template <typename T, template<typename> typename X>
class Base<X<T>> {
// ...
};
template <typename T>
class Derived: public Base<Derived<T>>{
// ....
};
Then you can use a promotion from the bottom as mentioned by #Jarod42:
X<T> f(void) {
return *static_cast<X<T>*>(this);
}
Note that here you are making systematically a copy of the object and probably it is not what you want.
Another option is to modify a bit the architecture and use a covariant return type (it follows a minimal, working example):
template <typename T>
class Base {
T val;
public:
virtual const Base<T>& f(void) const {
return *this;
}
};
template <typename T>
class Derived: public Base<T> {
public:
virtual const Derived<T>& f(void) const {
return *this;
}
};
int main(void) {
Derived<int> B;
Derived<int> C = B.f();
}
Which one is better for you mostly depends on the actual problem.
Template methods allows to span a set of method instances for different static type of arguments. Automatic argument deduction avoids duplication of information.
We are faced with a situation in which the static type we would like to automatically deduce as a template argument is the type of the class instance itself. (On the call site, the type of the instance can be a more specialised type than the class in which the template method is declared.)
eg.
class Base
{
public:
template <class T_callingObject>
T_callingObject foo()
{
bar += 1;
// We have a strong guarantee on this cast only if T_callingObject
// is automatically deduced !
return static_cast<T_callingObject&>(*this);
}
private:
int bar;
};
class Derived : public Base
{
};
int main()
{
Base base;
Derived derived;
base = base.foo<Base>(); // we already know the type of base is Base
derived = derived.foo<Derived>(); // idem
}
The question is : Is there a way not to repeat the type of base and derived ?
Edit: CRTP on Base is not an option here, we need to have a common ancestor type.
This is generally addressed with CRTP (Curiously Recursive Template Pattern) by making Base a template itself:
template <typename D>
struct Base {
D& foo() { return static_cast<D&>(*this); }
};
and thus struct Derived: Base<Derived>.
The set of operations you can conduct on the D parameters is restricted (it is an incomplete time at the time Base<Derived> is instantiated), but in your simple case this works.
You are still left to wonder if someone will not inadvertently write struct Bar: Base<Foo> though, so this only reduces the problematic surface.
EDIT: if CRTP for Base is not allowed (which often happen), you can layer the abstractions:
struct Base { virtual ~Base() {} };
template <typename D>
struct BaseT: Base {
D& foo() { return static_cast<D&>(*this); }
};
struct Derived: BaseT<Derived> {};
Since in general if foo needs to know what D is, you no longer have a single unified type.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is there a way to prevent a class from being derived from twice using a static assert and type trait?
What I'd like to prevent is more than one of the C based template from being derived in D (i.e. there should only ever be one instance of C derived from). Was hoping for maybe a static assert in C or B that may solve this.
// My Classes
template <class T>
class A {};
class B {};
template <class T, class S>
class C : public B, public virtual A<T> {};
// Someone elses code using my classes
class D : public C<Type1, Type2>, public C<Type3, Type4>
{
};
As it stands, it's impossible for B or C to detect what else a more derived class inherits from, so you can't add an assertion there. However, by adding a "curiously recursive" template parameter, you can tell C what the derived class is. Unfortunately, this does require the derived class to give the correct template argument, and there's no way to enforce that.
You can then determine whether the derived class inherits from B in more than one way; it is a base class, but you can't convert a derived class pointer to B* (since that conversion is ambiguous). Note that this doesn't necessarily indicate multiple inheritance; the test will also fail if there's non-public inheritance.
So the best solution I can think of is:
#include <type_traits>
template <class T> class A {};
class B {};
template <class T, class S, class D>
class C : public B, public virtual A<T> {
public:
C() {
static_assert(
std::is_base_of<C,D>::value && std::is_convertible<D*,B*>::value,
"Multiple inheritance of C");
}
};
struct Type1 {};
struct Type2 {};
struct Type3 {};
struct Type4 {};
class Good : public C<Type1, Type2, Good> {};
class Evil : public C<Type1, Type2, Evil>, public C<Type3, Type4, Evil> {};
int main()
{
Good good;
Evil evil; // Causes assertion failure
}
I had to put the assertion in the constructor rather than the class definition, since some of the types are incomplete when the class template is instantiated. Unfortunately, this means that the error will only be reported for classes that are actually instantiated.
In the CRTP pattern, we run into problems if we want to keep the implementation function in the derived class as protected. We must either declare the base class as a friend of the derived class or use something like this (I have not tried the method on the linked article). Is there some other (simple) way that allows keeping the implementation function in the derived class as protected?
Edit: Here is a simple code example:
template<class D>
class C {
public:
void base_foo()
{
static_cast<D*>(this)->foo();
}
};
class D: public C<D> {
protected: //ERROR!
void foo() {
}
};
int main() {
D d;
d.base_foo();
return 0;
}
The above code gives error: ‘void D::foo()’ is protected with g++ 4.5.1 but compiles if protected is replaced by public.
It's not a problem at all and is solved with one line in derived class:
friend class Base< Derived >;
#include <iostream>
template< typename PDerived >
class TBase
{
public:
void Foo( void )
{
static_cast< PDerived* > ( this )->Bar();
}
};
class TDerived : public TBase< TDerived >
{
friend class TBase< TDerived > ;
protected:
void Bar( void )
{
std::cout << "in Bar" << std::endl;
}
};
int main( void )
{
TDerived lD;
lD.Foo();
return ( 0 );
}
As lapk recommended, problem can be solved with simple friend class declaration:
class D: public C<D> {
friend class C<D>; // friend class declaration
protected:
void foo() {
}
};
However, that exposes all protected/private members of derived class and requires custom code for each derived class declaration.
The following solution is based on the linked article:
template<class D>
class C {
public:
void base_foo() { Accessor::base_foo(derived()); }
int base_bar() { return Accessor::base_bar(derived()); }
private:
D& derived() { return *(D*)this; }
// accessor functions for protected functions in derived class
struct Accessor : D
{
static void base_foo(D& derived) {
void (D::*fn)() = &Accessor::foo;
(derived.*fn)();
}
static int base_bar(D& derived) {
int (D::*fn)() = &Accessor::bar;
return (derived.*fn)();
}
};
};
class D : public C<D> {
protected: // Success!
void foo() {}
int bar() { return 42; }
};
int main(int argc, char *argv[])
{
D d;
d.base_foo();
int n = d.base_bar();
return 0;
}
PS: If you don't trust your compiler to optimize away the references, you can replace the derived() function with the following #define (resulted in 20% fewer lines of disassembly code using MSVC 2013):
int base_bar() { return Accessor::base_bar(_instance_ref); }
private:
#define _instance_ref *static_cast<D*>(this) //D& derived() { return *(D*)this; }
After some I came with a solution that works event for private members of templated derived classes. It does not solves the problem of not exposing all the members of the derived class to the base, since it uses a friend declaration on the whole class. On the other hand, for the simple case, this does not requires repeating the base name, nor it's template parameters and will always work.
First the simple case when the derived is non-template. The base takes an additional void template parameter just to show that everything still works in the case of extra template parameters of the base. The only needed one, as per the CRTP, is the typename Derived.
//Templated variadic base
template <typename Derived, typename...>
struct Interface
{
using CRTP = Interface; //Magic!
void f() { static_cast<Derived*>(this)->f(); }
};
//Simple usage of the base with extra types
//This can only be used when the derived is NON templated
class A : public Interface<A, void>
{
friend CRTP;
void f() {}
};
The only thing needed for this to work is the using CRTP = Interface; declaration in the base and the friend CRTP; declaration in the derived.
For the case when the derived is itself templated the situation is trickier. It took me some time to come to the solution, and I'm sure it's still not perfect.
Most of the magic happens inside these templates:
namespace CRTP
{
template <template <typename, typename...> class _Base, typename _Derived, typename... _BaseArgs>
struct Friend { using Base = _Base<_Derived, _BaseArgs...>; };
template <template <typename, typename...> class _Base, typename ..._BaseArgs>
struct Base
{
template <template <typename...> class _Derived, typename... _DerivedArgs>
struct Derived : public _Base<_Derived<_DerivedArgs...>, _BaseArgs...> {};
};
}
Their usage is more or less straightforward. Two use the above templates several steps are needed.
First, when inheriting in the derived class the inherited-from base class, and it's optional parameters, needs to be given. This is done using CRTP::Base<MyBase, BaseOptional....>, where MyBase is the name of the class used for CRTP, and the BaseOptional... are template parameters that are passed to the base class as-is, directly after passing our derived class that is supplied in the next step. When the base class does not accepts any additional template parameters they can be omitted completely: CRTP::Base<MyBase>.
The next step is to introduce the derived class (the whole point of CRTP). This is done by following the above CRTP::Base<...> with a ::Derived<ThisDerived, DerivedOptional...>. Where ThisDerived is the class this is defined in, and DerivedOptional... are all the template parameters declared in this class'es template declaration. The optional parameters much be specified exactly as they appear in the class template declaration.
The last step is declaring the base class as a friend. This is done by declaring friend typename CRTP::Friend<MyBase, ThisDerived, BaseOptional...>::Base somewhere in the class. The BaseOptional... template perameters must be repeated exactly as they appear in the CRTP::Base<MyBase, BaseOptional...> that is inherited from.
Follows is an example of using a templated derived when the base does not depends on the templated types (but it still can take other template parameters, void in this example).
//Templated derived with extra, non-dependant types, passed to the base
//The arguments passed to CRTP::Base::Derived<, ARGS> must exactly match
// the template
template <typename T, typename... Args>
class B : public CRTP::Base<Interface, void>::Derived<B, T, Args...>
{
friend typename CRTP::Friend<Interface, B, void>::Base;
void f() {}
};
Next is an example for when the base depends on template parameters of the derived. The only difference from the previous example is the template keyword. An experiment shows that if the keyword is specified for the previous, non dependant, case the code also complies cleanly.
//Templated derived with extra dependant types passed to the base
//Notice the addition of the "template" keyword
template <typename... Args>
class C : public CRTP::Base<Interface, Args...>::template Derived<C, Args...>
{
friend typename CRTP::Friend<Interface, C, Args...>::Base;
void f() {}
};
Please note that these templates do not work for non-templated derived classes. I will update this answer when I find the solution, so a unified syntax could be used for all cases. The closest thing that can be done is just using some fake template parameter. Note that it still must be named and passed to the CRTP machinery. For example:
template <typename Fake = void>
class D : public CRTP::Base<Interface>::Derived<D, Fake>
{
friend typename CRTP::Friend<Interface, D>::Base;
void f() {}
};
Note that A, B, C & D are declared as class. That is, all their members are private.
Follows is some code that uses the above classes.
template <typename... Args>
void invoke(Interface<Args...> & base)
{
base.f();
}
int main(int, char *[])
{
{
A derived;
//Direct invocation through cast to base (derived.f() is private)
static_cast<A::CRTP &>(derived).f();
//Invocation through template function accepting the base
invoke(derived);
}
{
B<int> derived;
static_cast<B<int>::CRTP &>(derived).f();
invoke(derived);
}
{
C<void> derived;
static_cast<C<void>::CRTP &>(derived).f();
invoke(derived);
}
{
D<void> derived;
static_cast<D<>::CRTP &>(derived).f();
invoke(derived);
}
return 0;
}
The invoke free-standing templated function works for any class derived from the base.
Also shown is how to cast the derived to the base without the need to actually specify the name of the base.
Surprisingly, this does not depend on any system headers.
The full code is available here: https://gist.github.com/equilibr/b27524468a0519aad37abc060cb8bc2b
Comments and corrections are welcome.
I'm trying to implement a kind of CRTP (if I well understand what it is) with multiple inheritance.
My main goal is to have a unified way to access list of instances of each subclass.
May problem seems to reside in the namespace utilization.
Here is the code of the simplest version :
http://ideone.com/rFab5
My real problem is more similar to :
http://ideone.com/U7cAf
I have an additional warning using clang++ :
test.cpp:28:63: warning: static data member specialization of 'instances' must originally be declared in namespace 'NS1'; accepted as a C++0x extension [-Wc++0x-extensions]
template <> std::list<NS1::Derived*> NS1::Base<NS1::Derived>::instances;
^
test.cpp:15:34: note: explicitly specialized declaration is here
static std::list<T*> instances;
Problem has been updated since it does not behave the same using namespaces.
Problem re-edited to post code on Ideone
The problem is that you've tried to define the list variable wrong. You need to provide a definition for Base, in general- you don't just define it for the one part that happens to be Derived's subclass, unless it's an explicit specialization.
template<typename T> std::list<T*> NS1::Base<T>::instances;
http://ideone.com/Vclac
Compiles with no errors. There are no intermediates or anything like that required.
Changing Base() and Intermediary() to Base<U>() and Intermediary<Derived> in the constructors makes the code OK for GCC.
There is no reason to change the definition of instances in the second case: the template is identical as the first situation.
Afaik, you got the following options.
First, if Intermediate is always templated on the derived type, you don't need a list for it, because it will never be the most derived type. If it could be templated on other types / not be derived, you can add a defaulted non-type bool template parameter like so:
template<bool, class A, class B>
struct select_base{
typedef A type;
};
template<class A, class B>
struct select_base<false,A,B>{
typedef B type;
};
template<class T, bool IsDerived = false>
class Intermediate
: public select_base<IsDerived,
Base<T>,
Base<Intermediate<T> >
>::type
{
// ...
};
// derived use
class Derived : public Intermediate<Derived, true>
{
// ...
};
// non-derived use:
Intermediate<int> im;
If the intermediate class is not templated and does not already derive from Base, you need to derive from Base again in the most derived class:
class Derived : public Intermediate, public Base<Derived>
{
// ...
};
The big problem comes when the intermediate also derives from Base but is not templated. You can add a defaulted derived type, but that would make the non-derived use a bit more ugly:
#include <type_traits> // C++0x, use std::
//#include <tr1/type_traits> // C++03, use std::tr1::
struct nil_base{};
template<class Derived = nil_base>
class Intermediate
: public select_base<std::is_same<Derived,nil_base>::value,
Base<Intermediate<Derived> >, //
Base<Derived>
>::type
{
// ...
};
// derived use now without boolean flag
class Derived : public Intermediate<Derived>
{
// ...
};
// non-derived use a bit uglier
Intermediate<> im;
// ^^ -- sadly needed
The following compiles OK with MinGW g++ 4.4.1, MSVC 10.0, and Comeau Online 4.3.10.1:
#include <list>
template <class T>
class Base
{
protected:
Base()
{
instances.push_back(static_cast<T*>(this));
}
private:
static std::list<T*> instances;
};
template <class U>
class Intermediary : public Base<U>
{
protected:
Intermediary()
:Base<U>()
{
}
};
class Derived : public Intermediary<Derived>
{
public:
Derived()
:Intermediary<Derived>()
{
}
};
template<class Derived> std::list<Derived*> Base<Derived>::instances;
int main()
{}
The instances definition is copied verbatim from your question.
I say as Isaac Newton, I frame no hypotheses!
Cheers & hth.,