I've looked through several on-topic questions but it didn't help, sorry if duplicated.
Why is Inner an incomplete type there? Where is the circular dependence?
P.S. NOT_USED is a placeholder class to keep specialization partial
template <class A>
struct Outer
{
template <class NOT_USED, class Enabled = void>
struct Inner
{ static void inner() { std::cout << "not enabled\n"; } };
template <class NOT_USED>
struct Inner<NOT_USED, typename std::enable_if<std::is_same<int, A>::value>::type>
{ static void inner() { std::cout << "enabled\n"; } };
};
template <class A>
void call_inner(A& a)
{
Outer<A>::template Inner<void>::inner(); // #1
}
int main()
{
int intVar = 10;
double doubleVar = 1;
call_inner(intVar); // OK
call_inner(doubleVar); // Error at #1: incomplete type ‘Outer<double>::Inner<void>’ used in nested name specifier
}
UPDATE
If I change the second specialization to (NOT_USED->Type, is_same<int, A> -> is_same<int, Type>)
template<typename Type>
struct Inner<Type, typename std::enable_if<std::is_same<int, Type>::value>::type>
{ static void inner() { std::cout << "enabled\n"; } };
And call_inner to (Note Inner<void>->Inner<T>)
template <class T>
void call_inner(T& t)
{
Outer<T>::template Inner<T>::inner();
}
Everything compiles. Why is that? Apparently, the dependence on Outer template parameter somehow changes instantiation process?
A possible fix:
template <class A>
struct Outer
{
template <class NOT_USED, typename T = A, class Enabled = void>
struct Inner
{ static void inner() { std::cout << "not enabled\n"; } };
template <class NOT_USED, typename T>
struct Inner<NOT_USED, T,
typename std::enable_if<std::is_same<int, T>::value
&& std::is_same<A, T>::value>::type>
{ static void inner() { std::cout << "enabled\n"; } };
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With