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.
Related
I'm trying to figure out how the template method generation works inside a class.
I've found code that describes the functionality which I would like to use but cannot understand how are the methods being generated.
Desired functionality is the automatic creation of methods that are templated based on the std::tuple arguments.
Code snippet was taken from:
https://commschamp.github.io/comms_protocols_cpp/
Here's the code:
template <typename TCommon, typename TAll>
class GenericHandler;
template <typename TCommon, typename TFirst, typename... TRest>
class GenericHandler<TCommon, std::tuple<TFirst, TRest...> > :
public GenericHandler<TCommon, std::tuple<TRest...> >
{
using Base = GenericHandler<TCommon, std::tuple<TRest...> >;
public:
using Base::handle; // Don't hide all handle() functions from base classes
virtual void handle(TFirst& msg)
{
// By default call handle(TCommon&)
this->handle(static_cast<TCommon&>(msg));
}
};
template <typename TCommon>
class GenericHandler<TCommon, std::tuple<> >
{
public:
virtual ~GenericHandler() {}
virtual void handle(TCommon&)
{
// Nothing to do
}
};
Example of usage:
class Message
{
public:
Message() = default;
virtual ~Message() {};
};
class X : public Message
{
public:
X() = default;
virtual ~X() {}
int x;
};
class Y : public Message
{
public:
Y() = default;
virtual ~Y() {}
int y;
};
using AllMessages = std::tuple<X,Y>;
class Handler : public GenericHandler<Message, AllMessages> {};
int main()
{
X x;
Handler h;
h.handle(x);
std::cout<<"Hello World";
return 0;
}
As I understand the template <typename TCommon, typename TFirst, typename... TRest> class GenericHandler<TCommon, std::tuple<TFirst, TRest...> > generates the handle() method and when the std::tuple is empty then the template <typename TCommon> class GenericHandler<TCommon, std::tuple<> > is used.
How does using Base::handle; work in this example?
How does GenericHandler inheritance work in this case template <typename TCommon, typename TFirst, typename... TRest> class GenericHandler<TCommon, std::tuple<TFirst, TRest...> > : public GenericHandler<TCommon, std::tuple<TRest...> >?
What is the process of generating the template methods?
Edit: I'm bound to C++ 11, but I'm interested in what can be done on the newer versions of C++.
How does using Base::handle; work in this example?
It's explained by its comment:
// Don't hide all handle() functions from base classes
The template class inherits from a parent template class, which also has its implementation of handle(). In the template's handle():
this->handle(static_cast<TCommon&>(msg));
Since this has a handle() (which just happens to be where this function call is made), normally overload resolution would find this handle() and only this handle().
However this ends up calling the parent class's handle(), thanks to the using declaration which has the effect of pulling in the parent class's handle(), which then gets picked by overload resolution. This is one of the fundamental rules of overload resolution, if you have:
pointer->method();
and the class has a method(), overload resolution stops, and will not include any method()s from the parent class. Here the intent is to call the parent class's method. The using declaration has the effect of adding the parent class's method to the subclass's namespace, and include it in any overload resolution.
The same thing can probably be accomplished without the using declaration, and by calling
this->Base::handle(static_cast<TCommon&>(msg));
explicitly.
Edit: I'm bound to the C++ 11, but I'm interested what can be done on the newer versions of C++.
The newer versions of C++ still work the same way.
Given a base class using CRTP, I'm looking at declaring a member in the base template class where the type is dependent of the derived class.
While the following works as intended:
template <class T> class BaseTraits;
template <class T> class Base {
using TypeId = typename BaseTraits<T>::TypeId;
TypeId id;
public:
Base() { id = 123; }
TypeId getId() { return id; }
};
class Derived;
template <> class BaseTraits<Derived> {
public:
using TypeId = int;
};
class Derived : public Base<Derived> {};
int main(int argc, char ** argv) {
Derived foo;
return foo.getId();
}
I wonder if I could simplify the implementation. I could add a second template parameter to the Base template, and make BaseTraits simpler or even get rid of it. However the above snippet is already an attempt to remove the second template parameter. I'm looking at solutions that doesn't involve a second template parameter for Base.
I've tried something like the following but it doesn't compile:
error: invalid use of incomplete type 'class Derived'
template <class T> class Base {
using TypeId = typename T::TypeId;
TypeId id;
public:
Base() { id = 123; }
TypeId getId() { return id; }
};
class Derived : public Base<Derived> {
public:
using TypeId = int;
};
int main(int argc, char ** argv) {
Derived foo;
return foo.getId();
}
UPDATE:
I'm limited to c++14.
Base must be a template.
Performance is a must.
Is it possible to make a member type directly dependent on the derived class? Taking appart the result type of a member function declared with auto (deduced return type), it is not possible.
So the use of a type-trait as you do in your solution is the best and only solution.
The reason is that a base class must be a complete type when the derived class is defined: the compiler must first instantiate and parse the base class definition before it parses the derived class definition, C++ standard N4140 [derived.class]/2 (bold is mine):
The type denoted by a base-type-specifier shall be a class type that is not an incompletely defined class;[...]
What about something like this:
template <typename T, typename TypeId> class Base
{
private:
TypeId id;
public:
Base() { id = 123; }
TypeId getId() {return id;}
};
class Derived : public Base<Derived, int> {};
This is kind of simplified, but you pay some price for it.
#include <any>
template <class T> class Base {
std::any id; // expensive, but cannot have T::TypeId here
public:
Base() : id(123) {}
auto getId() {
return std::any_cast<typename T::TypeId>(id);
} // T::TypeId is OK inside a member function
};
class Derived : public Base<Derived> {
public:
using TypeId = int;
};
Why not reversing the class hierarchy?
template <class T>
class Base : T {
using TypeId = typename T::TypeId;
TypeId id;
public:
Base() { id = 123; }
TypeId getId() { return id; }
};
struct BasicDerived {
using TypeId = int;
};
using Derived = Base<BasicDerived>;
Actually, I thought some more... this isn't too unpleasant:
You could have a binding struct, could even be written as a macro, declared just before the real class.
The binding struct defines the enum and an incomplete typedef to the real class.
The template is defined before all of that, but uses typename to defer its dependency, but it is instanced by the real class and only dependant on the binding struct
template <class ThatClassWrapper>
class MyBase
{
protected:
typedef typename ThatClassWrapper::TypeId TypeId;
typedef typename ThatClassWrapper::RealClass ThatClass;
TypeId typeIdValue;
TypeId GetTypeId() { return typeIdValue; }
std::vector<ThatClass*> storage;
};
class SomeClass;
namespace TypeIdBinding
{
struct SomeClass
{
enum TypeId
{
hello, world
};
typedef ::SomeClass RealClass;
};
}
class SomeClass: public MyBase<TypeIdBinding::SomeClass>
{
public:
bool CheckValue(TypeId id)
{ return id == typeIdValue; }
};
Note that the real class is using TypeId as defined in the template base, and the named members are not directly visible. You could fix that by having the template Base derive from the binding struct (confirmed that it compiles that way). though I actually like that in c++11 you can export or typedef just the enum typename from another namespace and use that type name as a prefix for the enum members, helping to avoid name pollution.
To be honest you have hit the wall of hard circular dependencies.
Any way out will be smelly.
Two template arguments seems like a small price in the end.
Could you declare a dummy template class that takes Derived and TypeID? I don't think it gains you anything, though.
Is TypeID:Derived a 1:1 mapping? Would it feel better to over-represent that 1:1 mapping with another helper template to back-look-up Derived from TypeID? Note that TypeID would need to be defined outside the Derived class to do this.
Does TypeID really need to be defined inside the class? Could it leach off the passed-in definition in Base to support the existing use of the internal typedef?
Can you double-include? Split or macriose your definition of derived so that typeid is in a base class definition that can be included before the template? This DerivedBase could be declared in a namespace and contain a typedef link back to the full Derived class so Base can find it for references.
This question is considering explicit instanciation of template classes.
Consider a template class B<T> derived from another template class A<T>. I want to explicitly instanicate B<T> because its methods are to be called from dynamic linking, so the methods must be instanciated although they are not called in the code itself. Of course, also methods inherited from A<T> will be called, so they must be instanciated as well.
It seems that C++ does NOT instanciate base classes when explicitly instanciating a template class, as asked in this question:
Do Explicit Instantiations of C++ Class Templates Instantiate Dependent Base Classes?
Example:
template<typename T>
class A{ void foo(){...} };
template<typename T>
class B : public A<T> {}
template class B<int>; // This will NOT instanciate A<int>::foo()!!!
Of course, I also need to instanciate all base classes. However, I don't want to burden the client code with this because the class hierarchy may be very deep. Consider a class hierarchy involving 10 or more template classes. The client should not be urged to write 10 explicit template instanciations. This is not only a lot of writing; it will also break when I introduce changes to the class hierarchy.
Instead, I want to achieve somehow that whenever B<T> is instanciated, then so are all its base classes. I tried simply instanciating the base class in B itself like this:
template<typename T>
class B : public A<T> {
template class A<T>; // Does not compile!
}
But this does not compile. Are there other ways that could achive this?
Maybe not elegant but at least workable: provide a macro to instantiate the template and require the user to use the macro in stead of manual instantiation:
// in A.hpp
#define INSTANTIATE_A(T) template class A<T>;
// in B.hpp
#define INSTANTIATE_B(T) \
INSTANTIATE_A(T) \
template class B<T>;
And if you prefer "polluting" the class interface to enforcing the use of an instantiation macro: add a protected member that calls all other member functions of the template and the version in the base class. Example:
template<typename T>
class A
{
void foo() {...}
protected:
void instantiate() { foo(); }
};
template<typename T>
class B : public A<T>
{
void bar() {...}
protected:
void instantiate() { A<T>::instantiate(); bar(); }
};
template class B<int>; // Now works as expected
Update:
Alternative to the second solution: take the function pointer of all members and save them to a temporary variable:
template<typename T>
class A
{
void foo() {...}
protected:
void instantiate() { void (A::*p)() = &A::foo; }
};
template<typename T>
class B : public A<T>
{
void bar() {...}
protected:
void instantiate() { A<T>::instantiate(); void (B::*p)() = &B::foo; }
};
I want to do:
template <class Derived=BattleData>
class BattleData : public BattleCommandManager<Derived> {
};
But obviously BattleData isn't declared, so I tried a forward declaration:
template <class T> class BattleData;
template <class Derived=BattleData>
class BattleData : public BattleCommandManager<Derived> {
};
But then I get
error: "wrong number of template parameter on the second line, with
BattleData.
I really fail to see a solution to this!
Edit:
The reason I'm doing this is because I want to be able to use BattleData directly as a class, but I also want to be able to subclass it in which case I have to specify the derived class as the second template parameter.
For example let's say the corpus of my BattleData class is :
template <class Derived> class BattleData: public BaseClass<Derived> {
void foo1(){};
void foo2(){};
void foo3(){};
}
And I have a subclass
template class SubBattleData: public BattleData<SubBattleData> {
void foo1(){};
}
I would still want, in some cases, to be able to write code like this:
BattleData *x = new BattleData(...);
I can't even do the following without being able to use default arguments:
BattleData<BattleData> *x = new BattleData<BattleData>(...);
On one side, the reason functions aren't virtualized in the BattleData class is the benefit of having no virtual function. The other reason it doesn't work for me is that one of the parent CRTP classes invokes functions only if they're present in the derived type (using decltype(Derived::function) and enable-if like structures), and fall back to default behavior otherwise. Since there can be a great deal of those functions with a particular design pattern (like a CRTP that reads a protocol with many different cases and processes a case a particular way only if the derived class specify the corresponding function, otherwise just transfer it without processing).
So those functions can be present in SubBattleData and not BattleData, but both classes would work fine if instantiated, yet it's impossible to instantiate BattleData.
You should be able to accomplish your original design goals more naturally than the above. You can't use the actual Derived typename as the default clearly because what you're really trying to write is the following:
template <class Derived=BattleData <BattleData <BattleData <...>>>
class BattleData : public BattleCommandManager<Derived> {
};
You get the idea. Instead, just use a placeholder like void:
template <typename T = void>
class BattleData : public BattleCommandManager <
typename std::conditional <
std::is_same <T, void>::value,
BattleData <void>,
T
>::type>
{
};
Disclaimer: I did not compile the above.
Can't you use an Empty class for the second template parameter?
template <class T=DataContainer, class Derived=BattleData<T, Empty> >
class BattleData : public BattleCommandManager<Derived> {
};
I don't see what you are trying to do. What is wrong with
template <class T=DataContainer>
class BattleData : public BattleCommandManager< BattleData<T> > {
};
If you specify Derived to be something else than the actual derived class static polymorphism is not going to work and CRTP becomes somewhat useless anyway.
Edit: From what I have gathered this is what you want to in abstract terms:
template <class Derived>
struct Base {
void interface() {
static_cast<Derived*>(this)->implementation();
}
};
template<typename T>
struct Derived : Base<Derived> {
// dummy so we get you example
T t;
void implementation() {
std::cout << "derived" << std::endl;
}
};
struct Derived2 : public Derived<int> {
// hide implementation in Derived
// but still have Base::interface make the right call statically
void implementation() {
std::cout << "derived2" << std::endl;
}
};
There is no way I know of that you can make this work. Another
approach would be to use policy classes instead of CRTP. They are
compatible with inheritance and you can achieve similar behaviour.
template<typename Policy>
struct BattleCmdManager : public Policy {
using Policy::foo;
};
template<typename T>
struct BattleData {
// ...
protected:
void foo();
};
struct BattleData2 : public BattleData<int {
// ...
protected:
void foo();
};
Here is how I solved it:
template <class Derived> class BattleDataInh: public BaseClass<Derived> {
void foo1(){};
void foo2(){};
void foo3(){};
};
template class SubBattleData: public BattleDataInh<SubBattleData> {
void foo1(){};
};
class BattleData : public BattleDataInh<BattleData> {
};
And that way, I can add any other template parameters too. The solution was in front of my eyes the whole time but I didn't see it...
I'm wanting to invoke a specialized templated function by using a pointer to it's base type. I'm not sure if this possible so I'm open to suggestions and/or alternatives. Here is an example of my situation:
class CBase {};
class CDerivedClass : public CBase {};
template<class T>
int func<T>(T &x) { ... };
template<>
int func<CDerivedClass>(CDerivedClass &x) { ... };
I have another function that manages a list of CBase pointers and then calls the func() function.
void doStuff()
{
CBase *foo[10] = { ...... };
for (int i = 0; i < 10; ++i)
func(*foo[i]);
}
Is there a way to get the derived type, so that func(CDerivedClass &) is called?
What about Template Subclassing? This idiom allows you to use compile-time polymorphism in C++. The cost of it is higher verbosity (such as specifying the whole class hierarchy up to the current class). In your case:
template <typename TSpec> class Klass {};
template <typename TSpec> struct SpecTag {};
template <typename TSpec> class Klass<SpecTag<TSpec> > {};
template <typename TSpec>
int func(Klass<TSpec> &x) { ... };
template <typename TSpec>
int func(Klass<SpecTag<TSpec> > &x) { ... };
The "Visitor" pattern comes to the rescue in this case. It enables polymorphic behavior in an algorithm implemented outside the class. Some support code is required inside the class, but new algorithms can later be added, existing algorithms modified, etc., without affecting the class.
Alternative solution : from your example, it's obvious that you just should to use a virtual method in CBase, so you just have to define a virtual function in CBase and an overriding function in the derived class.