For practical reasons, I've got a class like
template <class A>
class CRTP
{
template <int (A::*Member)()>
int func(void * obj)
{
int result
// Do something with Member, like
// result = (reinterpret_cast<A*>(obj)->*Member)();
return result;
}
};
The template <void (A::*Member)()> is a requirement, it cannot be passed as an argument.
And I also have a class Base
class Base : public CRTP<Base>
{
int aMemberOfBase() {...}
};
And its derived which I want to also inherit CRTP
class Derived : public CRTP<Derived>, public Base
{
int aMemberOfDerived() {...}
};
In some member of Derived, I'll do something like
func<&Derived::aMemberOfDerived>(this);
func<&Base::aMemberOfBase>(this);
Is that possible ?
(Well, VC++ compile only the first line and don't want to read about the second one... but Derived should have the members
template <int (Base::*Member)()> int func(void * obj);
template <int (Derived::*Member)()> int func(void * obj);
which looks strange, I admit it. But the following piece of code
template <void (Base::*Member)()> int func() {return 0;}
template <void (Derived::*Member)()> int func() {return 1;}
compiles and return func<&Base::someMember>() != func<&Derived::someMember>(), because the signature of the template is not the same and can't be the same.)
I must admit that I'm not well award of what the standard says. But is the inheritance pattern I'm trying to make allowed? And if yes, why one of the line doesn't compile?
Moreover, if I declare
class Derived : public Base, public CRTP<Derived>
instead of
class Derived : public CRTP<Derived>, public Base
I get compile time error (on all the func<...>(...)), which means that there's something wrong somewhere.
On the other hand, I know that
template <class A, int (A::*Member)()> int func(void * obj)
would remove the need of a CRTP, but it's painfull to write func<Derived, &Derived::aMember>(). Is there a workaround like
template <class Class, void (Class::*Member)()> class A
{
void func(void * obj) {...(reinterpret_cast<Class*>(obj)->*Member)();...}
};
template <typename Signature> class B;
template <typename Class, typename Member>
class B<&Class::Member> : public class A<Class, &Class::Member> {};
which would allow B<&Base::Derived>().func(somePtrToBase)?
You can disambiguate by qualifying the name of the base member template. The following should work:
template <typename A> struct CRTP
{
template <int (A::*Member)()> int func();
};
struct Base : CRTP<Base>
{
int aMemberOfBase();
};
struct Derived : CRTP<Derived>, Base
{
int aMemberOfDerived();
void foo()
{
CRTP<Derived>::func<&Derived::aMemberOfDerived>();
CRTP<Base>::func<&Base::aMemberOfBase>();
}
};
I made everything public to avoid getting bogged down in access control details.
Related
Let's say I have two template classes Foo<A,C,E> and Foo<A,B,C,D,E,F>. I want the former to automatically be derived from the latter. How can that be done?
My motivation for this: I want to use Foo<A,C,E> and Foo<A,B,D>. They need to be placed in some base class declaration. But if I homogenize them into some FooBase base class, it will lose all the properties of Foo<Ts...> (which has template member functions, so I cannot make them virtual in FooBase and define the overrides in the Foo derived classes). So if I just use Foo<A,B,C,D,E,F> as the base class definition, then everything should work out fine. Below illustrates the problem at hand:
struct FooBase { // Fruitless attempt to homegenize A and B defined below.
// template <int N> virtual void run() = 0; // No good, of course
};
template <typename... Ts>
struct Goo {
template <int N> void run() { } // This needs to be called by Foo<Ts...>
};
template <typename... Ts>
struct Foo : Goo<Ts...>, FooBase {
// template <int N> virtual void run() override { Goo<Ts...>::run<N>(); }
};
using A = Foo<int, char>;
using B = Foo<double, char>;
struct Thing {
FooBase *foo1, *foo2;
Thing (FooBase* f, FooBase* g) : foo1(f), foo2(g) { }
template <int N> void run() { foo1->run<N>(); foo2->run<N>(); }
};
int main() {
A* a = new A;
B* b = new B;
Thing thing(a,b);
thing.run<5>();
}
I would like to build the following classes. Base class is defining functions to be implemented, Derived implements this interface.
template <class T, class V>
class IBase
{
public:
virtual void foo(const typename V::t_args&) =0;
};
template<class T>
struct T_args
{
T z;
};
class Derived : public IBase<double, Derived>
{
public:
typedef T_args<double> t_args;
Derived() {}
void foo(const t_args& x)
{ /* do some stuff */ }
};
Compiler is complaining about Derived as an imcomplete type; I can't understand the reason why.
Is there any mean to get this class structure right?
I'm forced to code with c++98, but I'm interested for any solution in c++11 and above.
In your base template class:
virtual void foo(const typename V::t_args&) =0;
This is referencing some inner class or type called t_args of its V template parameter. When referencing a class member, the class's definition must be complete (in order to figure out what t_args is). You are attempting to use this template class as follows:
class Derived : public IBase<double, Derived>
You're passing in Derived for your V, however its class definition is incomplete. If the template base class only referenced its V parameter, it is generally "ok". However your template requires its template parameter type to be complete, because it needs to know what the heck that t_args is, and your derived class is not complete until it's fully defined. But it cannot be fully defined until its base class is fully defined. Sort of like a chicken vs egg situation.
There is no turnkey solution to this kind of a circular reference, of sorts. The only thing that can be done is restructure the class, so your "argument" type is an independent class, rather than the derived class.
Another workaround is to use some traits class:
// The traits class
template <typename T> struct Arg;
template <class T, class V>
class IBase
{
public:
virtual ~IBase() {}
virtual void foo(const typename Arg<V>::t_args&) = 0; // V can be incomplete here
// but Arg<V> should be complete
};
// So go to define Arg<Derived>:
// Result class
template<class T>
struct T_args
{
T z;
};
// Forward declaration, Arg<V> accept incomplete type
class Derived;
// Specialization for Derived
// should not use internal of Derived as it is incomplete
template <>
struct Arg<Derived>
{
typedef T_args<double> t_args;
};
// Now definition of Derived
class Derived : public IBase<double, Derived>
{
public:
typedef Arg<Derived>::t_args t_args; // Should probably go in IBase for ease usage
Derived() {}
void foo(const t_args& x) /* override */
{ /* do some stuff */ }
};
Demo
After reading the explanation by Sam Varshavchik, here is a potential workaround of my problem by adding the t_args class in the template signature of the base class:
template <class V, class Args>
class IBase
{
public:
typedef Args t_args;
virtual void foo(const Args&) =0;
};
template<class T>
struct T_args
{
T z;
};
template <class T>
class Derived : public IBase<Derived<T>, T_args<T> >
{
public:
typedef typename Derived::IBase::t_args t_args;
Derived() {}
void foo(const t_args&)
{ /* do some stuff */ }
};
Is it possible for a specialized version of a class to share some or all functionalities of the original template class?
i.e. consider there is a template class,
template <typename T>
class A
{
A()
{}
A(const A& ref)
{}
void f1()
{
//do something
}
void f2()
{
//do something
}
void f3()
{
//do something
}
}
and it has a specialized version for a specific datatype, which only intend to add some addition functionalities to the generic version in addition the original generic functionalities.
template<>
class A<int>
{
void f4()
{
//do something
}
}
now what I specifically want is that this specialized version to be sharing everything from its generic version including the constructors if possible.
It is usually possible to implement that by restructuring the class hierarchy:
template <typename T>
class A_base
{
// All the f1() functions, et. al, implemented here
};
template<typename T> class A : public A_base<T> {
public:
// An empty shell of a class, with the constructor
// forwarding its arguments to the superclass.
template<typename ...Args> A(Args && ...args)
: A_base(std::forward<Args>(args)...)
{
}
};
template<>
class A<int> : public A_base<int>
{
// Same constructor.
void f4()
{
//do something
}
};
You end up moving all class methods, class members, into a base class, with your template class consisting of nothing more than deriving from the base class template; and an empty facade otherwise.
Then, your specialization derives from the base class the same way, and adds its own methods.
Another alternative is to implement this kind of derivation "backwards".
// Empty template class.
template<typename T> class A_extra {};
// Your specialization, with the extra method:
template<>
class A_extra<int> {
void f4()
{
}
};
// And the template class inherits from it:
template<typename T> class A : public A_extra<T> {
// Your template class
};
Depending on the particular details of your template class, one or the other approach should work; or some variation on the same theme.
I want to derive a type Test from a templated type Base which I specialise on the derived type (i.e. Base<Test>).
Inside the templated type, I want to make use of a typedef defined in the derived type (the template parameter).
However, I get this compile error:
error C2039: 'X' : is not a member of 'Test'
Here is the code snippet:
template <typename T>
class Base
{
protected:
void func(typename T::X x) {}
};
class Test : public Base<Test>
{
public:
typedef int X;
};
Is this doable, and if so, what is the fix I need to make?
(I see a couple of answers for this kind of problem but it looks like my scenario isn't fixed by prefixing typename - is it something to do with deriving from a template specialised with the derived type?)
Alternatively to the typedef, you can also declare the type as second template argument in the base class:
template <typename T, typename X>
class Base
{
protected:
void func(X x) {}
};
class Test : public Base<Test, int>
{
public:
// typedef int X;
};
You have a circularity which cannot be resolved with forward declarations. But this will work, although (I suspect) not quite so strongly defined as you wanted.
template <typename T>
class Base
{
protected:
template<typename Y>
void func(Y x) {}
};
class Test : public Base<Test>
{
public:
typedef int X;
};
If func were public, then you could then write
Test t;
Test::X x;
t.func(x)
which is satisfactory for any use of the Curiously Recurring Template Pattern I think of.
This works for me:
template <typename T> struct Traits;
template <typename Derived>
class Base
{
protected:
void func(typename Traits<Derived>::X x) {}
};
class Test;
template <> struct Traits<Test>
{
typedef int X;
};
class Test : public Base<Test>
{
};
I'm not sure about this behavior, maybe someone can clarify it. But as I understand by the moment you do : public Base<Test> the type name X doesn't exists (since is declared below).
If you create a wrapper class before making the inheritance the type would exists by the moment you do the inheritance and the template instantiation will work.
This compiles with VC++ 2013
template <typename T>
class Base
{
protected:
void func(typename T::X x) {}
};
class TestWrapper
{
public:
typedef int X; //Declared, now it exists for the compiler
};
class Test
:public Base<TestWrapper> //Compiles correctly
{
};
Regarding CRP if I want to implement a slight variation of it (using template template parameter) I get a compile error:
template <template <typename T> class Derived>
class Base
{
public:
void CallDerived()
{
Derived* pT = static_cast<Derived*> (this);
pT->Action(); // instantiation invocation error here
}
};
template<typename T>
class Derived: public Base<Derived>
{
public:
void Action()
{
}
};
I am not exactly sure one would chose this form (that does not compile for me) instead of using this though (this works)
template <typename Derived>
class Base
{
public:
void CallDerived()
{
Derived* pT = static_cast<Derived*> (this);
pT->Action();
}
};
template<typename T>
class Derived: public Base<Derived<T>>
{
public:
void Action()
{
}
};
This should compile as well. We just need to get the other template parameter specified explicitly
template <typename T, template <typename T> class Derived>
class Base
{
public:
void CallDerived()
{
Derived<T>* pT = static_cast<Derived<T>*> (this);
pT->Action(); // instantiation invocation error here
}
};
template<typename T>
class Derived: public Base<T,Derived>
{
public:
void Action()
{
}
};
In the first example, the class template actually takes template template parameter, not just template parameter, as you've written:
template <template <typename T> class Derived>
class Base
{
//..
};
So this code doesn't make sense:
Derived* pT = static_cast<Derived*> (this);
pT->Action(); // instantiation invocation error here
Here Derived is a template template argument which needs template argument which you didn't provided to it. In fact, in the CallDerived() function, you cannot know the type you need to provide to it, in order to do what you intend to do.
The second approach is the correct solution. Use it.