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.
Related
Please find below some usage of C++ template. I am not able to fully understand these from syntactical and semantically point of view, e.g.,
First this is declared, which I know :
template <class T>
class Queue {// some other statements};
Then this is declared, which I understood partially, need to know what does it mean from syntactical and semantically point of view :
template <class T>
class IntermittentQueue : Queue<T> {// some other statements};
And finally this statements, which I again didn't understand fully
template <class T>
typename IntermittentQueue<T>::Node* IntermittentQueue<T>::getNode(const node_ptr nodePtr) {// some other statements };
template <class T>
class IntermittentQueue : Queue<T> { /* some other statements */ };
This defines a new template class:
template <class T>
class IntermittentQueue { }
that at the same time inherits from another one, such as:
class Base { };
class Derived : Base { };
Solely, that in this case, the base class is an instantiation of another template class:
template <typename T>
class Base { };
class Derived : Base<int> { };
using the derived class' template parameter as template argument (and now we are back at the original code again...).
template <class T>
typename IntermittentQueue<T>::Node* IntermittentQueue<T>::getNode(const node_ptr nodePtr)
{ /* some other statements */ };
This is the implementation of one of the member functions of a template class. Step by step:
template <class T> // the class we are speaking off is a template class
typename IntermittentQueue<T>::Node* // return value of the function
IntermittentQueue<T>::getNode // function name with (template) class scope specified
// (just as with SomeClass::someMemberFunction)
(const node_ptr nodePtr) // function parameter(list)
{ /* some other statements */ }; // function body
Fine so far, but the return type might need further explanation:
typename IntermittentQueue<T>::Node*
The function returns a pointer to an object of inner class type Node of (template) class IntermittentQueue:
IntermittentQueue<T>::Node*
As inner type is a dependent type, you need to explicitly tell the compiler that this actually is a type at all, this is what the typename keyword then is used for; for details: there's already another question to the topic.
Just a side note here: Having typedefs for pointers (node_ptr) is bad practice, that's just information hiding and does not serve anything valuable for (the exception from: the pointer serves as a handle to some internal resource and is not intended to be dereferenced anywhere outside – then explicitly hiding the pointer nature is valid).
I'm looking to call a method of a base class A from a child class D that inherits it through C::A and B::A.
template <class PType>
class A
{
public:
template <class ChildClass>
void Func( void )
{
std::cout << "Called A<PType>::Func<ChildClass>" << std::endl;
}
};
template <class PType>
class B : public A<PType>
{
};
template <class PType>
class C : public A<PType>
{
};
class D : public B<int>, public C<int>
{
public:
D()
{
static_cast<B<int>*>( this )->A<int>::Func<D>();
static_cast<C<int>*>( this )->A<int>::Func<D>();
}
};
This works as expected, D calls both B::A::Func and C::A::Func with a template argument of the child class when initialized. This doesn't seem to work when D is a template class, however.
template <class PType>
class D2 : public B<PType>, public C<PType>
{
public:
D2()
{
//expected primary-expression before ‘>’ token
//expected primary-expression before ‘)’ token
static_cast<B<PType>*>( this )->A<PType>::Func< D2<PType> >();
static_cast<C<PType>*>( this )->A<PType>::Func< D2<PType> >();
}
};
The problem seems to be the template argument D2 to Func, but can't figure it out beyond that.
When you are working with a name whose value/type/template status is dependent on a template type parameter, you must disambiguate which one it is for the compiler manually.
This is to make the parsing far easier, and able to be done long before you pass a type into the template.
You may think that is obviously a template function call, but the < and > could be comparisons, and the template functions could be values or types or whatever.
By default, such dependent names are assumed to be values. If you want them to treat one as a type, use typename. If you want to treat one as a template, use template as a keyword.
So something like this:
static_cast<B<PType>*>( this )->template A<PType>::template Func< D2<PType> >();
now, when you are interacting with a fully instantiated template this is not required. So:
static_cast<B<int>*>( this )->A<int>::Func< D2<PType> >();
consists of a fully instantiated template type B<int>, so A's category is no longer dependent on a (locally undetermined) template argument. Similarly, ->A<int> is a fully instantiated template type, so ::Func is no longer dependent on a (locally undetermined) template argument.
I need to use a template class which is defined in another template class as parameter of another template as return value in template method. I know it sounds complicated, code below explains it better. Problem is that the code cannot be compiled, it ends with following error:
type/value mismatch at argument 2 in template parameter list for 'template<class T, template<class> class Policy> class Result'
expected a class template, got 'CDummy<T2>::Policy2'
but I'm pretty sure that given class fulfills needs. Problem is that the method, which uses it, is template too and so compiler does not know what exactly CDummy<T2>::Policy2 is. If the Policy2 would not be template, but regular class or if I could fill its argument, I would use typename which would tell the compiler not to worry about it, but how can this be done with template?
// I cannot change this interface - it's given by a library
template <class T, template <class> class Policy>
class Result : public Policy<T>
{
T data;
};
template <class T>
class Policy1
{
};
// I use this for allowing Policy2 to change behaviour according Dummy
// while it keeps template interface for class above
template <class Dummy>
class CDummy
{
public:
template <class T>
class Policy2 : public Policy1<T>
{
};
};
// Both variables are created ok
Result<int, Policy1 > var1;
Result<int, CDummy<float>::Policy2 > var2;
// This is ok, too
template <class T>
Result<T, Policy1 > calc1()
{
return Result<int, Policy1>();
}
// But this ends with the error:
// type/value mismatch at argument 2 in template parameter list for 'template<class T, template<class> class Policy> class Result'
// expected a class template, got 'CDummy<T2>::Policy2'
template <class T1, class T2>
Result<T1, CDummy<T2>::Policy2 > calc2() // <-- Here is the generated error
{
typedef typename DummyTypedef CDummy<T2>;
return Result<T1, DummyTypedef::Policy2>();
}
Notes:
I use gcc 4.7.3 32bit in GNU/Linux Ubuntu 13.04. 32 bit.
For various reasons, I cannot use C++11 standard (yet) and so I cannot use template typedefs
I believe that the name CDummy<T2>::Policy2 is a dependent name in that context and that you should use the template keyword to inform the compiler that it is indeed a template.
template <class T1, class T2>
Result<T1, CDummy<T2>::template Policy2 > calc2() // <-- Here is the generated error
// ^^^^^^^^
additionally the implementation of that same function seems to be wrong also. The order of typedefs is original name, new name, and CDummy<T2> is known to be a type (i.e. there is no need for the typename):
typedef CDummy<T2> DummyTypedef;
The return statement would then be:
return Result<T1, DummyTypedef::template Policy2>();
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;
};
Example, I want to specialize a class to have a member variable that is an stl container, say a vector or a list, so I need something like:
template <class CollectionType, class ItemType>
class Test
{
public:
CollectionType<ItemType> m_collection;
};
So I can do:
Test t = Test<vector, int>();
t.m_collection<vector<int>> = vector<int>();
But this generates
test.cpp:12: error: `CollectionType' is not a template
What you want is a template template parameter:
template <template <typename> class CollectionType, class ItemType>
class Test
{
public:
CollectionType<ItemType> m_collection;
};
What we did here is specifying that the first template parameter, i.e. CollectionType, is a type template. Therefore, Test can only be instantiated with a type that is itself a template.
However, as #Binary Worrier pointed in the comments, this won't work with STL containers since they have 2 template parameters: one for the elements type, the other one for the type of the allocator used for managing storage allocation (which has a default value).
Consequently, you need to change the first template parameter so that it has two parameters:
template <template <typename,typename> class CollectionType, class ItemType>
class Test
{
public:
CollectionType<ItemType> m_collection;
};
But wait, that won't work either! Indeed, CollectionType awaits another parameter, the allocator... So now you have two solutions:
1 . Enforce the use of a particular allocator:
CollectionType<ItemType, std::allocator<ItemType> > m_collection
2 . Add a template parameter for the allocator to your class:
template <template <typename,typename> class CollectionType,
class ItemType,
class Allocator = std::allocator<ItemType> >
class Test
{
public:
CollectionType<ItemType, Allocator> m_collection;
};
So as you see, you end up with something rather complicated, which seems really twisted to deal with STL containers...
My advice: see Greg Rogers' answer for a better approach :)!
Why not do it like this?
template <class CollectionType>
class Test
{
public:
CollectionType m_collection;
};
Test t = Test<vector<int> >();
t.m_collection = vector<int>();
If you need the itemtype you can use CollectionType::value_type.
EDIT: in response to your question about creating a member function returning the value_type, you do it like this:
typename CollectionType::value_type foo();
You add the typename because CollectionType has not been bound to an actual type yet. So there isn't a value_type it could look up.
Comeau online likes this:
#include <vector>
template <template <class T, class A = std::allocator<T> > class CollectionType, class ItemType>
class Test
{
public:
CollectionType<ItemType> m_collection;
};
void foo()
{
using std::vector;
Test<vector,int> t = Test<vector, int>();
t.m_collection = vector<int>();
}