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>();
Related
A class WithTTMember has a template member type named TT.
struct WithTTMember {
template<typename> using TT = void;
};
Another class ExpectTT takes a template template parameter:
template< template<typename> typename TT >
struct ExpectTT {};
ExpectTT<WithTTMember::TT> can be successfully instantiated.
A third class ExpectTWithTT expects a template parameter with a template member type named TT, and instantiates ExpectTT using it:
template<typename T>
struct ExpectTWithTT {
using X = ExpectTT<typename T::TT>; // this doesn't compile
};
I expect ExpectTWithTT<WithTTMember>::X to be the same type as ExpectTT<WithTTMember::TT>. However the code above is fails to compile.
I tried injecting the faulty line with a combination of template and typename keywords following compiler messages and my instinct, but I couldn't get it to work.
How can I express what I want?
Any C++ version is fine.
You should use template keyword to tell that T::TT is a template.
template<typename T>
struct ExpectTWithTT {
using X = ExpectTT<T::template TT>;
// ^^^^^^^^
};
I am trying to use a member type of a template class, which does not depend on any template parameters of the template class. I would like to keep the type as the member type due to its logic, but I do not want to specify the unnecessary template parameters of the class whenever I want to use the member type outside the class.
Consider the following:
class Dummy { };
// Template class
template<typename T>
class A {
public:
template<typename T2>
class MemberType : public T2 {
public:
T2 t2;
};
};
int main()
{
typename A<Dummy>::template MemberType<Dummy> m1; // okay
typename A::template MemberType<Dummy> m2; // not okay!
return 0;
}
I got the following compiler error when I try to compile using g++:
error: ‘template<class T> class A’ used without template parameters
typename A::template MemberType<Dummy> m2; // not okay!
Is there any workaround for this?
I am trying to use a member type of a template class, which does not
depend on any template parameters of the template class.
As a nested type within class A<T>, MemberType does depend on the template parameter T.
i.e. A<T>::MemberType<T2> and A<U>::MemberType<T2> are distinct classes.
What you want to do is not possible. A template is just a template. There is very little you can do with it before actually instantiating it for a concrete type. There could be a specialization for A that has no nested MemberType at all.
I would like to keep the type as the member type due to its logic,
[...]
...but it seems the logic is something else: The MemberType does not depend on A, hence it should not be part of a template that depends on A.
Sloppy speaking template<typename T> can be read as "everything that follows depends on T". Even if you think it does not, there could always be a specialization that changes anything inside A. If you want MemberType to not depend on T then declare it outside A.
Everything in a template is dependent on the parameter(s) - meaning a template-specialization might not even have class MemberType.
But you can make a default parameter - you still need to write <> though (but you can omit template usually - even typename, but I left that):
class Dummy { };
// Template class
template <class T = void>
class A {
public:
template<typename T2>
class MemberType : public T2 {
public:
T2 t2;
};
};
int main()
{
typename A<Dummy>::MemberType<Dummy> m1; // okay
typename A<>::MemberType<Dummy> m2; // also ok
return 0;
}
As others have pointed out, this somewhat looks like an anti-pattern though - since the inner type is not dependent on the parameter of the outer template class.
Is there any workaround for this?
MemberType is a type dependent from a template parameter so, necessarily, you have to pass through the containing template a template parameter to define it
typename A<SomeType>::template MemberType<AnotherType> m2;
Taking in count that your not interested in external SomeType parameter, the best workaround I can imagine is the use of a using as follows (or something similar)
template <typename T>
using MemberType_t = typename A<T>::template MemberType<T>;
to reduce typewriting.
The following is a full compiling simplified example
#include <type_traits>
class Dummy { };
template <typename>
struct A
{
template <typename T2>
struct MemberType : public T2
{ T2 t2; };
};
template <typename T>
using MemberType_t = typename A<T>::template MemberType<T>;
int main ()
{
typename A<Dummy>::template MemberType<Dummy> m1;
MemberType_t<Dummy> m2; // compile
static_assert( std::is_same<decltype(m1), decltype(m2)>::value, "!" );
}
I try to do the following, I think the example should be self-explaining:
template <class CLASS, class PARAM>
void call(){
CLASS<PARAM>::do_something();
}
On the angular brackets between CLASS and PARAM on line 3, the compiler says:
error: expected unqualified-id
Can I fix this problem or is it not allowed what I try to do?
template <
template <typename T> class CLASS,
typename PARAM>
void call()
{
CLASS<PARAM>::do_something();
}
The template parameter CLASS is declared to be a class, or also a typename, I.e. the name of a type.
template<typename X> struct A;
Here A isn't a type, it's a template. To obtain a type, you need to "apply"(*) the template: A<int>.
If you write CLASS<PARAM>, you're trying to apply a type to a type. This won't work. It's like trying to call a value 42(parameter), only on the type level.
So you need to specify that CLASS is something which can be applied, that it's a template:
template <typename T> class CLASS
So, for reference, the complete solution is:
template <template <typename T> class CLASS, class PARAM>
void call(){
CLASS<PARAM>::do_something();
}
(*) A template is a function on type level: It takes one or more types, and returns a new type.
In addition to the answers given by #DanielJour and #Nasser, I want to mention that the name T of the type name for the template template parameter CLASS can be omitted, because it is not used. So, the condensed solution would look like this:
template <template <typename> class CLASS, typename PARAM>
void call()
{
CLASS<PARAM>::do_something();
}
Reference: Template Template Parameters.
I have a class that needs to use some sort of map. By default, I want to use std::map, but I also want to give the user the ability to use something different if they want (e.g. std::unordered_map or maybe even a user created one).
So I have code that looks like
#include <map>
template<class Key, template<class, class> class Map = std::map>
class MyClass {
};
int main() {
MyClass<int> mc;
}
But then, g++ complains
test.cpp:3:61: error: template template argument has different template parameters than its corresponding template template parameter
template<class Key, template<class, class> class Map = std::map>
^
test.cpp:8:14: note: while checking a default template argument used here
MyClass<int> mc;
~~~~~~~~~~~^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/map:781:1: note: too many template parameters in template template argument
template <class _Key, class _Tp, class _Compare = less<_Key>,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:3:21: note: previous template template parameter is here
template<class Key, template<class, class> class Map = std::map>
^~~~~~~~~~~~~~~~~~~~~~
1 error generated.
So it looks like g++ is unhappy that std::map has default arguments.
Is there a way I can allow Map to be any sort of template that can accept at least two template arguments?
I would prefer to stick with C++98 if I can, but I'm open to C++11.
The problem is that your template template parameter has only two template parameters, as opposed to map, which has four.
template<class Key, template<class, class, class, class> class Map = std::map>
class MyClass {
};
Or
template<class Key, template<class...> class Map = std::map>
class MyClass {
};
Should compile. However, to avoid such problems, try to take the map type instead, and extract the key type via the corresponding member typedef. E.g.
template <class Map>
class MyClass {
using key_type = typename Map::key_type;
};
Your code will compile in C++17. A long-standing defect report of the C++ Core Working Group (CWG 150) was resolved (by P0522R0) in time for C++17.
cppreference.com also discuss this here, and include a helpful example:
template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template <class ...Types> class C { /* ... */ };
template<template<class> class P> class X { /* ... */ };
X<A> xa; // OK
X<B> xb; // OK in C++17 after CWG 150
// Error earlier: not an exact match
X<C> xc; // OK in C++17 after CWG 150
// Error earlier: not an exact match
Testing with my version of GCC (8.3.0), I find that using the -std=c++17 flag will successfully compile your program; while using earlier versions of C++ (e.g. -std=c++14 or -std=c++11) will fail.
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.