I am thinking about using curiously recurring template pattern for my application. However, I would like the classes to operate on the user defined types. I would like to understand if it is possible to create a structure similar to the one shown below:
template <class T_leaftype>
class BaseTrajectoryPoint {
};
template <class MyType>
class MyTrajectoryPoint: public BaseTrajectoryPoint<MyTrajectoryPoint> {
private:
MyType A;
};
The code above fails to compile with the following error:
type/value mismatch at argument 1 in template parameter list for ‘template class BaseTrajectoryPoint’
Are there any alternative ways of approaching the problem? I would like to use static polymorphism, but I would prefer to define all possible methods in the base class.
template <class T_leaftype>
class BaseTrajectoryPoint {
};
template <class MyType>
class MyTrajectoryPoint: public BaseTrajectoryPoint<MyTrajectoryPoint<MyType> > {
private:
MyType A;
};
MyTrajectoryPoint isn't a type, it's template; when you pass it as template parameter, it's seen as template<typename> class T>, not template<class T> - and the latter is what your base class is expecting. But MyTrajectoryPoint<MyType> names a type, so you can use it as template parameter of your base class.
Of course, you can change declaration of BaseTrajectoryPoint to template<template<class> class T_leaftype>, but then you would have to use class template as template parameter, never a complete type.
What our friend Griwes said is correct, although if you know that every class that will inherit BaseTrajectoryPoint is a template class, you can do the following:
template<template < class > class TLeaf> // << This means: It is expected a template class as parameter
class BaseTrajectoryPoint{
};
template <class MyType>
class MyTrajectoryPoint: public BaseTrajectoryPoint<MyTrajectoryPoint> >{
private:
MyType A;
};
Related
How can I specify template parameter to be of a certain type i-e it must have implemented an interface (the template parameter must be a derived class of a specific base class)
Heres the interface (abstract base class)
class baseActionCounter{
public:
virtual int eat()=0;
virtual int drink()=0;
};
Now I want my template parameter to be of type baseActionCounter
Heres the templated class
//imaginary template syntax in the line below. Is there a way of achieving this behavior?
template <class counterType : baseActionCounter>
class bigBoss{
counterType counter;
public:
int consumerStats(){
//I am able to call member function because I know that counter object has eat() and drink()
//because it implemented baseActionCounter abstract class
return counter.eat() + counter.drink();
}
};
I can also just derive my bigBoss class from baseActionCounter but I want to know how to achieve this behavior with templates.
Also, template specialization is not suitable as there is just one BigBoss class for any implementor of baseActionCounter class.
Yes, you can use std::is_base_of to check the type, e.g.
template <class counterType, std::enable_if_t<std::is_base_of_v<baseActionCounter, counterType>>* = nullptr>
class bigBoss {
Or
template <class counterType>
class bigBoss {
static_assert(std::is_base_of_v<baseActionCounter, counterType>, "counterType must derive from baseActionCounter");
...
};
Or use concept (since C++20).
template <class T>
concept Derived = std::is_base_of_v<baseActionCounter, T>;
template <Derived counterType>
class bigBoss {
BTW: std::is_base_of also returns true if the base class baseActionCounter is specified; if that's not what you want you can combine the condition with std::is_same.
I'm trying to experiment with CRTP but I am puzzled on why the following code does not compile.
template<template<class...> class CBase>
struct ComponentX : public CBase<ComponentX>
{
// This does NOT compile
};
template<template<class...> class CBase>
struct ComponentY : public CBase<int>
{
// This does compile
};
Do you know if there is some limitation for template template parameters in the case of CRTP?
A class template name stands for the "current specialization" (i.e. it is an injected class name) only after the opening { of the class template definition, inside its scope. Before that, it's a template name.
So CBase<ComponentX> is an attempt to pass a template as an argument to CBase, which expects a pack of types.
The fix is fairly simple:
template<template<class...> class CBase>
struct ComponentX : public CBase<ComponentX<CBase>> // Specify the arguments
{
// This should compile now
};
ComponentX<CBase> is the name of the specialization you wish to provide as a type argument.
Is there anyway to specialize a trait template for a nested class? I've tried it in the three places noted below, each with the given error. I've seen questions regarding specializing nested template classes, but that's not what I'm trying to do here-- I'm trying to specialize a trait class that is used by the nested class.
The TraitUser class makes use of the definitions within the Trait as specialized to a specific type T. Perhaps most relevantly, it uses a trait member to initialize a base class.
template<T>
class TraitUser:public X<typename Trait<T>::Type>
{
//Trait<T> gets used in here
};
//class A;
//class A::B; <-incomplete type used in nested name
//template<>
//struct Trait<A::B>
//{};
class A
{
private:
//class B;
//template<> <-explicit specialization at class scope
//struct Trait<B>
//{};
class B:TraitUser<B>
{};
};
//template<> <- specialization after instantiation
//struct Trait<A::B>
//{};
It looks like the root of the trouble is not being able to forward declare a nested class and also not being able to define a specialization inside a class declaration.
I'm trying this under clang using C++11.
There's some complicated declaration ordering here:
template <class T>
struct Trait;
template <class T>
struct X
{};
template<class T>
class TraitUser:public X<typename Trait<T>::Type>
{
//Trait<T> gets used in here
};
class A
{
private:
class B;
};
template<>
struct Trait<A::B>
{
typedef int Type;
};
class A::B : public TraitUser<B>
{};
Modern C++ Design gives the following example:
template <class T> struct EnsureNotNull
{
static void Check(T*& ptr)
{
if (!ptr) ptr = GetDefaultValue();
}
};
template
<
class T,
template <class> class CheckingPolicy = EnsureNotNull,
template <class> class ThreadingModel
>
class SmartPtr
: public CheckingPolicy<T>
, public ThreadingModel<SmartPtr>
{
...
T* operator->()
{
typename ThreadingModel<SmartPtr>::Lock guard(*this);
CheckingPolicy<T>::Check(pointee_);
return pointee_;
}
private:
T* pointee_;
};
I couldn't figure how ThreadingModel template would be constructed in a fashion that It could accept SmartPtr as parameter, in my mind some crazy recursion is going to happen. How can this be possible?
Edit:
I've tried Potatoswatter (sorry lol) comment:
template <class SmartPtr> struct SingleThreadingModel
{
class Lock
{
public:
Lock(SmartPtr&)
{
}
};
};
but it did'nt worked.
here is the error that gcc is giving me:
main.cpp:28:35: error: type/value mismatch at argument 1 in template parameter list for ‘template<class> class ThreadingModel’
main.cpp:28:35: error: expected a type, got ‘SmartPtr’
You are trying to pass SmartPtr as a template type argument to ThreadingModel. SmartPtr however is a template, not a concrete type, and the injected class-name is not available in the inheritance list.
Also note that you can't just use default arguments for template parameters in arbitrary positions (§14.1/11):
If a template-parameter has a default template-argument, all subsequent template-parameters shall have a default template-argument supplied.
Your code with those issues fixed:
template
<
class T,
template <class> class ThreadingModel,
template <class> class CheckingPolicy = EnsureNotNull
>
class SmartPtr
: public CheckingPolicy<T>
, public ThreadingModel<SmartPtr<T, ThreadingModel, CheckingPolicy> >
// ^ .... now passing a concrete class .... ^
{
T* operator->() {
// the following use of SmartPtr is fine as it is the injected class-name:
typename ThreadingModel<SmartPtr>::Lock guard(*this);
// ...
}
};
Note that while Modern C++ Design is an excellent book, it can't replace a good basic book on templates like Vandevoorde/Josuttis.
The recursion is OK because passing a specialization as a template parameter does not directly cause it to be instantiated.
(ThreadingModel<SmartPtr> in the base list is just shorthand for ThreadingModel< SmartPtr< T, CheckingPolicy, ThreadingModel > > which uses the "current specialization.")
I don't know what ThreadingModel is supposed to do, so I can't implement it, but it should have a declaration of the form
template< class Client > class MyThreading
and it cannot access anything inside Client outside of MyThreading member functions. If you use Client and Client depends on MyThreading, then infinite recursion does happen.
I have a template class in which I am specializing a couple of methods. For some reason, when I added a specialization for a struct, it seems to be conflicting with the specialization for bool. I am getting a type conversion error because it is trying to set the struct = bool (resolving to the wrong specialization). Here is some code
.h:
typedef struct foo {
...
}
template <class T> class bar {
template <class T> void method1() {...}
template <> void method1<bool>() {...}
template <> void method1<foo>() {...}
}
.cpp
template class bar<bool>;
template class bar<foo>;
I am getting the error inside method1<bool> because it is setting T=foo instead of resolving it to method1<foo>.
Any ideas?
The first part of your code is already incorrect. C++ does not support explicit specialization of "nested" (member) templates without explicit specialization of the enclosing template.
In the context of your code, it is illegal to explicitly specialize template method method1 without explicitly specializing the entire class template bar.
If your member template function member1 depended on some parameters, you could use overloading instead of template specialization as a workaround. But since it doesn't, you have to redesign you templates somehow. What you do above is, once again, illegal in C++.
The errors you get further down can easily be (and most probably are) induced by that original problem.
P.S. The description of the problem you posted implies that your code compiles. What you posted should not compile for the reasons described above. This suggests that you are posting fake code. Post real code.
(EDITED)
You may try the following, which delegates the method implementation to a templated helper class.
.h:
typedef struct Foo {
...
}
template<class T_Bar, class T2> struct BarMethod1;
template <class T> class Bar
{
template<class T2> void method1(...)
{
BarMethod1<Bar, T2>(...)(...);
}
}
template <class T_Bar, class T2> class BarMethod1
{void operator()(...){...}};
template <class T_Bar> class BarMethod1<T_Bar, bool>
{void operator()(...){...}};
template <class T_Bar> BarMethod1<T_Bar, Foo>
{void operator()(...){...}};
.cpp
template class Bar<bool>;
template class BarMethod1<Bar<bool>, bool>;
template class BarMethod1<Bar<bool>, Foo>;
template class Bar<Foo>;
template class BarMethod1<Bar<Foo>, bool>;
template class BarMethod1<Bar<Foo>, Foo>;