嵌套模板类型的部分特化在 VC++ 2012 编译器中生成 "internal error"

Partial specialization of nested template types produces "internal error" in VC++ 2012 compiler

在下面的示例中,我有一个对象 class,它定义了一个引用 class。两者都接受可变性作为模板参数。在 'obj' 是 'Const' 的情况下,我想禁止 'Non_Const' 类型的引用。该示例在 Visual C++ 2012 中生成了不明确的消息 "An internal error has occurred in the compiler,"。这应该编译吗?如果不是,为什么,还有其他方法可以完成同样的事情吗?

enum Mutability {Const, Non_Const};

template <typename T, Mutability U>
class Obj
{
public:
    template <Mutability V>
    class Ref
    {
    public:
        Ref() {}

        friend class Obj;
    };

    Obj() {}
};

template <typename T>
class Obj<T, Const>::template Ref<Non_Const>
{
private:
    Ref() {}
}; //error C1001: An internal error has occurred in the compiler

int main()
{
    Obj<int, Const>::Ref<Non_Const> test;
}

您要做的是部分显式特化成员 class 模板。那只是无效的 C++,与基本上尝试部分专门化成员的想法相同。不幸的是,VC 试图编译它时崩溃了,gcc 并没有真正给出有用的错误,但 clang 恰好:

main.cpp:21:31: error: cannot specialize a dependent template
class Obj<T, Const>::template Ref<Non_Const>
                              ^

但是您可以明确地专门化整个过程:

template <>
template <>
class Obj<int, Const>::Ref<Non_Const>
{
private:
    Ref() {}
};

然后你唯一的编译错误是 Ref()private.

如果您想要做的是禁止在 UMutability::const 时将 V 实例化为 Ref,我们可以使用一些模板来强制执行此概念诡计:

(比我聪明的人可能会让这个更简单)

enum class Mutability {Const, Non_Const};

template<Mutability T>
struct ConstMutability: std::true_type{};

template<>
struct ConstMutability<Mutability::Non_Const>: std::false_type{};

到目前为止我所做的是将 Mutability::Const 映射到 std::true_type,并将 Mutability::Non_Const 映射到 std::false_type

现在我可以结合 std::enable_if 强制执行以下组合:

  • UConstVConst
  • U Non_Const, VConst
  • UNon_ConstVNon_Const

完整代码:

template <typename T, Mutability U>
class Obj
{
public:
    template <Mutability V, typename std::enable_if<
    std::is_same<ConstMutability<U>, ConstMutability<V>>::value || 
    (ConstMutability<V>::value && !ConstMutability<U>::value)
    >::type* = nullptr>
    class Ref
    {
    public:
        Ref() {std::cout << "Successfully created a Ref object" << std::endl;}

        friend class Obj;
    };

    Obj() {}
};

你可以这样测试:

int main()
{
    Obj<int, Mutability::Const>::Ref<Mutability::Const> test1; //pass
    //Obj<int, Mutability::Const>::Ref<Mutability::Non_Const> test2; // fail
    Obj<int, Mutability::Non_Const>::Ref<Mutability::Const> test3; // pass
    Obj<int, Mutability::Non_Const>::Ref<Mutability::Non_Const> test4; // pass
}

Live Demo