In your following function template:
template<typename T, typename... ARGS>
void foo(T::Common tc, ARGS... args);
T is in a non-deducible context. Therefore, doing:
foo(ac, 42, "Hello");
won't compile, because T can't be deduced from the function call arguments. You would need to explicitly pass A as an argument to the T template parameter:
foo<A>(ac, 42, "Hello");
However, note that T::Common will actually have to be preceded by the keyword typename, since Common is a type-dependent name:
template<typename T, typename... ARGS>
void foo(typename T::Common tc, ARGS... args);
Extracting the outer class type without giving up implicit type deduction
You could declare an outer_class_of<> class template for extracting the outer class. This template would be parameterized by the inner class type:
// primary template
template<typename>
struct outer_class_of;
Then, specialize this template for both A::Common and B:Common:
// specialization for A::Common
template<>
struct outer_class_of<A::Common> {
using type = A; // outer class of A::Common
};
// specialization for B::Common
template<>
struct outer_class_of<B::Common> {
using type = B; // outer class of B::Common
};
You can declare then an alias template for achieving C++14-like _t type traits:
template<typename T>
using outer_class_of_t = typename outer_class_of<T>::type;
This way, outer_class_of_t<A::Common> corresponds to A and outer_class_of_t<B::Common> to B.
Finally, you need to change your foo() function template definition to:
template<typename TCommon, typename... ARGS>
void foo(TCommon tc, ARGS... args) {
outer_class_of_t<TCommon> t(tc, args...);
}
When calling foo() with a A::Common or a B::Common object as function argument, TCommon will be deduced to A::Common or B::Common, respectively. outer_class_of<> is then applied on TCommon to obtain the type of the outer class.
Also, be ware of C++'s most vexing parse in:
A::Common ac();
What you want is actually:
A::Common ac{};
Otherwise, in the call to foo(), TCommon will be deduced to A::Common(*)() (i.e.: a pointer to function) instead of A::Common, since the former is declaring a function that takes no parameters and returns an A::Common object, whereas the latter is actually declaring an A::Common object.