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

问题描述 投票:3回答:2

当我从一个union的模板化基类继承并对其进行部分特化时,MSVC上的编译失败,因为禁止将unions作为基类(参见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> {
};
c++ templates template-meta-programming
2个回答
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
投票

你的部分专业化不是union

正如你所指出的那样,union不能用作基类,正如Justin指出的那样,使用union关键字进行部分特化是不合法的。

除此之外:由于某些原因,MSVC不介意使用union关键字,只是忽略部分特化的类键,并将其视为struct的定义。

gcc的情况下也会发生同样的事情。它抱怨不同的类键,但是一旦你将-fpermissive标志传递给编译器,你的例子就会编译,尽管vector<T, 2>是一个结构,而不是一个联合。

Demo

© www.soinside.com 2019 - 2024. All rights reserved.