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.
Related
I want to define function outside the template class as described below.
Already tried a lot of combinations for the second argument which is a template and takes default argument as well.
template <typename T>
class CustomAllocator
{
//My custom allocator
};
template <typename T, typename Allocator = CustomAllocator<T> >
class CustomContainer
{
void push_back();
};
/*I want to define push_back outside my class, tried everything.
Almost 4 hours spent through stackoverflow, fluentcpp and all sites*/
// What should be specified for Allocator here ?
template <typename T>
void CustomContainer<T,Allocator>::push_back(T value)
{
}
//OR
template <typename T>
void CustomContainer<T,CustomAllocator<> >::push_back(T value)
{
}
I expect it to be defined outside class
Actual getting compiler error, if it is simple type I could easily mention int,float etc. in the second argument.
Outside of your class definition, it will be unclear to a function what type Allocator is, so you have to redeclare it just like you redeclared T
template <class T, class Allocator>
void CustomContainer<T,Allocator>::push_back(T value)
{
// ...
}
(I'm assuming that DataType should be T)
Note that your declaration of push_back, in the class should match the definition:
template <typename T, typename Allocator = CustomAllocator<T> >
class CustomContainer
{
void push_back(T);
};
You may not use default template arguments for a member function of a template defined outside the template definition.
From the C++ 17 Standard (17.1 Template parameters)
... A default template-argument shall not be specified in the template-
parameter-lists of the definition of a member of a class
template that appears outside of the member’s class.
So just write
template <typename T, typename Allocator>
void CustomContainer<T, Allocator>::push_back( const T &value )
{
//...
}
Pay attention to the argument of the function. Your declaration of the function does not correspond to its definition.
I have JsonFormatter template class that is specialized for different types like arithmetic etc... in the following way:
template <class T, typename Enable = void>
class JsonFormatter;
template <class T>
class JsonFormatter<T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
{
};
it is not clear how to specialize it for a concrete type like std::string, for example? My first idea was something like this:
template <>
class JsonFormatter<std::string, std::true_type>
{
};
but this does not compile. When I use
JsonFormatter<std::string>
I get
"undefined class 'JsonFormatter<std::string,void>'"
The important point is that the specialization has to match the primary. In this case, the primary is set up such that the 2nd template parameter is going to be void - it's not intended to be provided by the user, it's just there to enable people to use enable_if.
std::true_type doesn't match void, which is why it doesn't work. When the user writes JsonFormatter<std::string>, the default argument will get instantiated as void - so they're looking for the specialization JsonFormatter<std::string, void>... which isn't what you provided.
You want:
template <>
class JsonFormatter<std::string, void>
{ };
Or even just:
template <>
class JsonFormatter<std::string>
{ };
Since the default argument will get filled in just fine.
This is how you specialize the template:
template <>
class JsonFormatter<std::string, void>
{
};
You can also use std::enable_if, but I don't recommend it since it a simple specialization is much easier. std::enable_if works correctly with SFINAE only. So it needs to depend on a template parameter:
template <class T>
class JsonFormatter<T, std::enable_if_t<std::is_same_v<T, std::string>>>
{
};
it is not clear how to specialize it for a concrete type like std::string, for example?
Have you tried simply with
template <>
class JsonFormatter<std::string>
{
};
?
Should works.
The second template parameter become void according the dafault value defined in the main version.
So first, apologies for terminology - I'm not sure if template prototype is the correct term. By this I mean :
template <class T, class X>
class TemplatePrototype
{
// code
};
I have a situation where I have a function that creates a template object based upon template arguments to that function.
template <class T, class X>
void doSomething()
{
TemplatePrototype<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
However, there are about 15 different versions of TemplatePrototype, which all have the same interface but different execution (TemplatePrototype is provided by another library). As a result, I have a lot of code that looks like this:
template <class T, class X>
void doSomethingWithOne()
{
TemplatePrototypeOne<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
template <class T, class X>
void doSomethingWithTwo()
{
TemplatePrototypeTwo<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
As a consequence of the architecture, I must know which TemplatePrototype I am going to use before I know the actual types T and X. I would like to see something like this:
template <class T, class X, class Prototype>
void doSomething()
{
Prototype<T, X> aPrototype;
aPrototype.doSomething();
}
But where I have specified part of the template arguments in advance - i.e I specify Prototype before I know T and X. Obviously, this is not possible in C++.
Equally, I cannot pass the Prototype as a template argument because it will still result in huge amounts of duplicate code.
Some important facts : I know the range of all possible inputs.
So I could theoretically use a macro to define each possible template specialisation and insert them into a container, which I would then use to access the specialisation I need. However, I am looking for a more 'elegant' solution - is it possible to pass template prototypes without specialising them as an argument to a template class, and then instantiate later when a function is called? Example:
template <class Prototype>
class Holder
{
template <class T, class X>
void doSomething()
{
Prototype<T, X> aPrototype;
aPrototype.doSomethingElse();
}
};
As far as I know this is impossible, but I was wondering if the SO community had some folks who know a solution?
EDIT:
So I have implemented this as my solution, thanks to the answers below!
#include <iostream>
template <typename T>
struct Foo
{
Foo() { aPtr = 0; }
T* aPtr;
};
template <template<typename> class C>
struct Bar
{
template <class T>
void doSomething()
{
C<T> aClass;
if (aClass.aPtr)
std::cout << "Hello world" << std::endl;
}
};
int main()
{
Bar<Foo> aFoo;
aFoo.doSomething<int>();
return 0;
}
This enables me to specify which TemplatePrototype I wish to use, before I can know the template parameters.
Yes, use a template template parameter, e.g.
template <typename T>
struct Foo
{
};
template <template<typename> class C>
struct Bar
{
};
then
Bar<Foo> b;
You're looking for template template parameters.
In the template parameter list, instead of just:
class TemplatePrototype
specify your prototype as a class template which itself has two template type parameters (without giving them a name here), like:
template<class,class> class TemplatePrototype
//^^^^^^^^^^^^^^^^^^^
This will result in a function like:
template <class T, class X,
template<class,class> class TemplatePrototype>
void doSomething()
{
TemplatePrototype<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
Invocation example:
doSomething<T, X, TemplatePrototypeOne>();
To become independent of the number of template parameters you pass to your "prototype" (here it was 2, namely T and X), you can use variadic templates (since C++11).
For this, first move the prototype template parameter to the first position:
template <template<class,class> class TemplatePrototype,
class T, class X>
Then, replace class T, class X with class ...Ts, which is a placeholder of an arbitrary number of type parameters. Also, in the template template parameter list, replace class,class with class.... And in the instantiation within the function implementation, replace <T, X> with <Ts...> to "expand" the parameter pack.
The result then looks like this:
template <template<class...> class TemplatePrototype,
class ... Ts>
void doSomething()
{
TemplatePrototype<Ts...> aTemplateTs;
aTemplateTs.doSomethingElse();
}
Live demo
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 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>;