So, first consider the following where template parameters are known implicitly from the function arguments:
#include <iostream>
using namespace std;
class A {};
class B {};
template <class T1, class T2>
class C {
T1 a;
T2 b;
};
template <class T1>
class D {
T1 a;
};
template <template<class, class> class TC, class TA, class TB>
void foo(TC<TA, TB> c) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(TD<TA> d){
std::cout << "T<T>" << std::endl;
};
int main() {
C<A,B> c;
D<A> d;
foo(c);
foo(d);
}
And output is as you'd expect:
T<T,T>
T<T>
However, what if I don't have an instance of class C
and D
so I need to explicitly call the correct overload? How would this be done? i.e., have a main()
that consists of:
int main() {
foo<C<A,B> >();
foo<D<A> >();
}
I've experimented with a few overloads of foo()
as shown below:
template <template<class, class> class TC>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD>
void foo(){
std::cout << "T<T>" << std::endl;
};
template <template<class, class> class TC, class TA, class TB>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(){
std::cout << "T<T>" << std::endl;
};
However, this (and all permutations I've been able to think of) simply results in a series of errors along the lines of the (abbreviated) output shown below
prog.cpp: In function 'int main()':
prog.cpp:44:18: error: no matching function for call to 'foo()'
foo<C<A,B> >();
^
prog.cpp:44:18: note: candidates are:
prog.cpp:19:6: note: template<template<class, class> class TC> void foo()
void foo() {
^
prog.cpp:19:6: note: template argument deduction/substitution failed:
prog.cpp:24:6: note: template<template<class> class TD> void foo()
void foo(){
^
prog.cpp:24:6: note: template argument deduction/substitution failed:
Is what I'm looking to do even allowable? If so, where am I messing up?
---- EDIT ----
So as apple apple pointed out if my main()
is as follows:
int main() {
foo<C, A, B>();
foo<D, A>();
}
I get the output as expected.
However, my real-world case winds up being more complex. I'll expand a bit here. The legacy code has (hundreds) of typedefs defined in headers elsewhere along the lines of:
typedef C<A, B> type_117;
typedef D<A> type_252;
The class I'm working on is templated and is instantiated with one of those typedefs as the templating argument. So something along the lines of:
template <class Type>
class Test
{
public:
Test();
SomeClass mSC;
}
Test::Test()
: mSC(foo<Type>())
{
};
where Test was instantiated as
Test<type_117> aTest;
So I've been trying to figure out how to write foo()
for this context. At the point I call foo()
within my Test
's initializer am I able to "decompose" it to produce the <C,A,B>
form? Or have I hit a roadblock and need to rework some of the existing framework?
template<class T>struct tag_t{constexpr tag_t(){}};
template<class T>constexpr tag_t<T> tag{};
these are type tags. They can be passed to functions without an instance of the type.
Template functions will deduce on them.
template <template<class, class> class TC, class TA, class TB>
void foo(tag_t<TC<TA, TB>>) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(tag_t<TD<TA>>){
std::cout << "T<T>" << std::endl;
};
at call site do foo(tag<type_117>)
and bob, as they say, is your uncle.
In C++98 (ick):
template<class T>struct tag_t{};
foo(tag_t<type_117>());