当我从一个union
的模板化基类继承并对其进行部分特化时,MSVC上的编译失败,因为禁止将union
s作为基类(参见1)。但是,如果我使用struct
作为我继承的主要模板,并且仅使用union
进行部分特化,它可以让我编译它就好了。我很好奇为什么会这样。另外我想知道下面的代码(2)是否符合标准,或者MSVC只允许我绕过标准。
(1)C ++标准(10.4 Unions [class.union])
“一个联合可以有成员函数(包括构造函数和析构函数),但它不应该有虚函数(10.6.2)。一个联合不应该有基类。一个联合不能用作基类。”
(2)例子(godbolt.org)
//template <typename T, std::size_t Size>
//↓ ↓ clearly illegal
//union vector_base {
// vector_base() : data() {}
// std::array<T, Size> data;
// }
template <typename T, std::size_t Size>
//↓ legal now?
struct vector_base
{
std::array<T, Size> data;
};
template <typename T>
union vector_base<T, 2>
{
std::array<T, 2> data;
struct { T x, y; };
};
template <typename T, std::size_t Size>
class vector : public vector_base<T, Size> {
};
此代码不合法。来自[temp.class]:
在类模板的重新声明,部分特化,显式特化或显式实例化中,类 - 密钥应与原始类模板声明([dcl.type.elab])同意。
class-key是class
,struct
或union
之一。
在你的情况下,你的部分特化是非法的,因为你以前使用union
时使用了struct
的类密钥。
要获得所需的行为,请在类中使用anonymous union:
template <typename T>
struct vector_base<T, 2>
{
union {
std::array<T, 2> data;
// Note that anonymous structs are non-standard, but supported in C11
struct { T x, y; };
};
};
但是,要小心这个union
;您可能想要访问非活动成员,但这是undefined behavior,除非工会成员共享common initial sequence。我不确定在这种情况下是否这样做,但我认为他们没有,因为std::array
是与T[2]
不同的类型,我甚至不确定T[2]
和T x, y
是否是一个共同的初始序列。