Reputation: 151
I'm trying to use a template template parameter as a default value for other template parameters but when I try to use the identifier (template template parameter name/id ) it cannot be found. I'm using VS 2013. The idea is that I have a "factory" class based on a specific type of template instantiation I need to return another object with the same number of parameters (4) BUT with the same specialization.
template<class T1, class T2,class T3, class T4>
class CommandBus
{...}
template <
template<class T1, class T2, class T3, class T4> class ListenerType,
//The Line bellow fails to compile, T1 is not visible
//E0020 identifier "T1" is undefine
class CommandBusType = CommandBus<T1, T2, T3, T4> >
class CommandBusFactory {
static auto Get() {
return CommandBusType{};
}
};
int main{
//Say I would Have some Object :
Listener<int, int ,int int> Listener;
//Withought the Factory I would have to manually generate a ComamndBus of the same specialization (int , int , int, int):
CommandBus<int,int,int,int> cmdBus;
//But I could use a factory, things should look like:
Listener<int, int ,int int> listener;
auto cmdBus = CommandBusFactory<Listener<int,int,int,int>>::Get();
}
I was expecting this to work but the compiler complains that for example identifier T1,T2 etc not found for the default value (CommandBus)for template parameter CommandBusType.
Is is possible to use template template arguments as default value for other template arguments?
Upvotes: 1
Views: 255
Reputation: 30135
It is not entirely clear what you are attempting here. The use of the template there will allow CommandBusFactory
to create different instantiations of the provided ListenerType
, rather than for them to be passed in, e.g.:
template <
template<class T1, class T2, class T3, class T4> class ListenerType,
class CommandBusType
>
class CommandBusFactory {
static auto Get() {
ListenerType<int, int, float, float> listener; // template params go here
ListenerType<std::string, std::string, double, double> listener2; // allowing different ones
return CommandBusType{};
}
};
int main() {
CommandBusFactory<Listener, SomeCommandBus> factory; // not here
}
If you do want to provide the ListenerType
up front, and then determine CommandBusType
from that, you might use typedefs, return values, or similar means (like containers having value_type
, etc.).
template<class T1, class T2, class T3, class T4> class CommandBus {};
template<class T1, class T2, class T3, class T4> class Listener
{
public:
typedef T1 t1;
typedef T2 t2;
typedef T3 t3;
typedef T4 t4;
};
template <
class ListenerType,
class CommandBusType = CommandBus<typename ListenerType::t1, typename ListenerType::t2, typename ListenerType::t3, typename ListenerType::t4>
>
class CommandBusFactory {
static auto Get() {
return CommandBusType{};
}
};
int main() {
CommandBusFactory<Listener<int,int,float,float>> factory;
}
Upvotes: 1
Reputation: 96236
The first template paramater of CommandBusFactory
is itself a template.
And yet, in main
you pass Listener<int,int,int,int>
to it, which is not a template, but a type. You need a type template parameter instead.
Then, to extract template arguments from that type you could use template specialization:
template
<
class X,
template <class, class, class, class> class Y
>
struct copy_template_params;
template
<
template <class, class, class, class> class X,
class A, class B, class C, class D,
template <class, class, class, class> class Y
>
struct copy_template_params<X<A,B,C,D>,Y>
{
using type = Y<A,B,C,D>;
};
template
<
class ListenerType,
class CommandBusType = typename copy_template_params<ListenerType,CommandBus>::type
>
class CommandBusFactory
{
public:
static auto Get()
{
return CommandBusType{};
}
};
Upvotes: 2