联合作为模板化基类的部分专业化

时间:2018-08-03 21:27:58

标签: c++ templates template-meta-programming

当我从模板化的基类union继承并对其进行部分专业化处理时,在MSVC上的编译失败,因为它禁止将union作为基类(请参见1)。 但是,如果我将struct用于我继承的主模板,而仅将union用于部分专业化,那么我可以对其进行编译。 我很好奇为什么会这样。另外,我想知道下面的代码(2)是否符合标准,还是MSVC只允许我绕过该标准。

(1)C ++标准(10.4联合[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> {
};

2 个答案:

答案 0 :(得分:4)

此代码不合法​​。来自[temp.class]

  

在重新声明,部分专门化,显式专门化或显式实例化类模板时,类密钥应与原始类模板声明([dcl.type.elab])保持一致。

class-keyclassstructunion之一。

在您的情况下,您的部分专业化是非法的,因为以前使用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是常见的初始序列。

答案 1 :(得分:1)

您的部分专业化不是union

您指出,union不能用作基类,并且Justin指出,使用union关键字进行局部专业化是不合法的。

此外,由于某种原因,MSVC不介意使用union关键字,而只是忽略了部分专业化的类关键字,并将其视为struct的定义。

gcc的情况下也会发生相同的情况。它抱怨类密钥不同,但是一旦-fpermissive标志传递给编译器,您的示例就可以编译,尽管vector<T, 2>是结构而不是联合。

Demo