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.
Related
I have a base class template and a class deriving from an instantiation of it:
template<typename T>
class Bar
{
template <T t>
void Foo();
};
class Derived : public Bar<int> {};
How should one implement Derived::Foo<0>() for example?
when trying this out:
template<>
void Derived::Foo<0>() { /* impl.. */}
i get the following compile error:
template-id 'Foo<0>' for 'Derived::Foo()' does not match any template declaration.
You cannot specialize it in the descendant; you can only add a signature that'll serve as an overload and delegate as necessary:
template<typename T>
class Bar
{
template <T t>
void Foo();
};
class Derived : public Bar<int> {
using Base = Bar<int>;
template <int t>
void Foo()
{
if constexpr(t == 0) {
/* impl... */
} else {
Base::Foo<t>();
}
}
};
Since the ADL / Koenig lookup of a class does not include template base class(es), I'd not expect any issues during overload resolution if you do it this way.
I try to create a templated class, which saves the template argument as a member variable (msg_).
Now the input of the class should allow normal types like int and shared_ptr<int>.
template <typename T>
class Foo {
public:
Foo<T>() {};
private:
T msg_;
};
My problem is if the class gets initialized with shared_ptr<int>, the shared_ptr has to get initialized:
this->msg_ = std::make_shared<T*>();
I tried to solve it like this:
Foo<T>() {
if (std::is_pointer<T>::value) {
this->msg_ = std::make_shared<T*>();
}
};
, but the problem is that is has to be solved on compile time. Otherwise I can not compile.
Do you know any patterns, which solve this issue?
Thank you! and
Best regards
Fabian
You might have specialization
template <typename T>
class Foo {
public:
Foo() {}
private:
T msg_;
};
template <typename T>
class Foo<std::shared_ptr<T>>
{
public:
Foo() : msg_(std::make_shared<T>()) {}
private:
std::shared_ptr<T> msg_;
};
or create function to initialize (with overload)
template <typename> struct tag{};
template <typename T>
T foo_default_init(tag<T>) { return {}; }
template <typename T>
std::shared_ptr<T> foo_default_init(tag<std::shared_ptr<T>>)
{
return std::make_shared<T>();
}
template <typename T>
class Foo {
public:
Foo() : msg_(foo_default_init(tag<T>{})){}
private:
T msg_;
};
I have a template class Context. I want to limit the user to use the specified type (Stratege1 but not Stratege2) that is derived from a specific class Base.
class Base {
public:
virtual void run() = 0;
};
class Stratege1 : public Base {
public:
virtual void run() {
printf("Stratege1 \n");
}
};
class Stratege2 {
public:
virtual void run() {
printf("Stratege2 \n");
}
};
template <typename T> class Context {
public:
void run() {
t.run();
};
private:
T t;
};
It may be OK if the user want to invoke like this:
Context<Stratege1> context;
context.run();
However I don't expect the user use (to avoid unexpectedly potential run-time issues)
Context<Stratege2> context;
context.run();
Because Stratege2 is not derived from Base class. Is there any elegant way to limit the concept during compilation?
Thanks for any suggestions.
Since C++11, you can static_assert something, this means get a nice compilation error when a compile-time check fails:
#include <type_traits> // is_base_of
template <typename T>
class Context {
static_assert(std::is_base_of<Base, T>::value,
"T must be a derived class of Base in Context<T>.");
public:
void run() {
t.run();
};
private:
T t;
};
For instance:
Context<NotBase> c2;
error: static_assert failed "T must be a derived class of Base in Context<T>."
-> static_assert(std::is_base_of<Base, T>::value,
note: in instantiation of template class 'Context<NotBase>' requested here
-> Context<NotBase> c2;
Full program demo
Use std::enable_if_t (equivalent to std::enable_if<B,T>::type) and std::is_base_of.
#include <type_traits>
template <typename T,
typename = std::enable_if_t<std::is_base_of<Base, T>::value> >
class Context {
public:
void run() {
t.run();
};
private:
T t;
};
Is there any elegant way to limit the concept during compilation?
Another possible solution is through partial specialization: the second template paramenter is true only if T is derived from base
template <typename T, bool = std::is_base_of<Base, T>::value>
class Context;
template <typename T>
class Context<T, true>
{
private:
T t;
public:
void run () { t.run(); };
};
So you have
Context<Stratege1> cs1; // compile
// Context<Stratege2> cs2; // compilation error
Unfortunately you can hijack Context explicating the second parameter
Context<Stratege2, true> cs2; // compile
I have a class template
template <class T>
class A
{
};
and very strange specialization
template <>
class A<class T*> : private A<void *>
{
};
Can anybody explain the meaning of this construction ?
The obfuscation declares a class T and specialize the template for T*
#include <iostream>
template <class T>
class A
{
public:
static void f() { std::cout << "Template" << '\n'; }
};
// Declare a class T and specialize the template for T*
template <>
class A<class T*> : private A<void *>
{
public:
static void f() { std::cout << "Specialization" << '\n'; }
};
class T {};
int main()
{
// Template
A<int*>::f();
// Specialization
A<T*>::f();
}
I think that the intended code would be:
template <class T>
class A<T *> : public A<void*>
{
};
That is a partial specialization that will be used for any pointer type, instead of the generic one. That is, any time A is instantiated using a pointer type, it will use this declearation instead of the generic one.
Naturally you need to instantiate, or otherwise spezialize the A<void*>, before this declaration, or else you will have an infinite recursion:
template class A<void*>;
This is a somewhat common idiom to force the compiler to reuse code. That is, you know that every instance of A<T*> is basically the same, as all pointers will behave identically under the hood. So you provide the full instantiation of A<void*> and then any other A<T*> inherits from it, doing the casts inline where needed.
Since A<T*> inherits from A<void*> it does not need to provide the bulk of the class code in its instantiation. Smaller code will hopefully will yield better performance.
Full example ahead, untested:
template <typename T>
class A
{
public:
A()
:m_data(0)
{}
void set(T x)
{ m_data = x; }
T get()
{ return m_data; }
//here there will be more complex operations
private:
T m_data;
//and a lot of data depending on T
};
template class A<void*>; //splicit instantiation
template <typename T>
class A<T*> : public A<void*>
{
private:
typedef A<void*> base_type;
public:
//only the public, and maybe protected, functions are needed
//but the implementation is one-line each
void set(T *x)
{ base_type::set(x); }
T *get()
{ return static_cast<T*>(base_type::get()); }
};
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.