嵌套模板类型的部分特化在 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
.
如果您想要做的是禁止在 U
为 Mutability::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
强制执行以下组合:
U
是 Const
,V
是 Const
U
Non_Const
, V
是 Const
U
是 Non_Const
而 V
是 Non_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
}
在下面的示例中,我有一个对象 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
.
如果您想要做的是禁止在 U
为 Mutability::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
强制执行以下组合:
U
是Const
,V
是Const
U
Non_Const
,V
是Const
U
是Non_Const
而V
是Non_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
}