嵌套说明符中使用的模板不完整类型

template incomplete type used in nested specifier

我已经查看了几个切合主题的问题,但没有帮助,抱歉,如果重复了。

为什么 Inner 是一个不完整的类型?循环依赖在哪里?

P.S。 NOT_USED 是一个占位符 class 以保持部分专业化

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
}

更新

如果我将第二专业更改为 (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"; } };

call_inner到(注Inner<void>->Inner<T>

template <class T>
void call_inner(T& t)
{
    Outer<T>::template Inner<T>::inner();
}

一切都编译。这是为什么?显然,对 Outer 模板参数的依赖以某种方式改变了实例化过程?

Clang 错误消息更明确:

ess.cpp:11:52: error: no type named 'type' in
      'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable
      this declaration
  ...Inner<NOT_USED, typename std::enable_if<std::is_same<int, A>::value>::type>
                                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~
ess.cpp:18:5: note: in instantiation of template class 'Outer<double>' requested
      here
    Outer<A>::template Inner<void>::inner(); // #1
    ^
ess.cpp:26:5: note: in instantiation of function template specialization
      'call_inner<double>' requested here
    call_inner(doubleVar); // Error at #1: incomplete type <BF>Outer<dou...

由于您有一个 enable_if 将实例化限制为 A == int,因此您无法实例化 Outer<double>::Inner<void>

可能的修复:

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"; } };
};