3

When I inherit from a templated base class that is a union and have partial specializations on it, the compilation on MSVC fails since it's forbidden to have unions as base classes (see 1). If I however use a struct for the primary template I inherit from and only use union for the partial specializations it lets me compile it just fine. I'm curious as to why that is. Also I'd like to know whether the below code (2) is standard compliant or MSVC only allowed me to get around the standard.

(1) C++ standard (10.4 Unions [class.union])

"A union can have member functions (including constructors and destructors), but it shall not have virtual (10.6.2) functions. A union shall not have base classes. A union shall not be used as a base class."

(2) Example (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> {
};
  • 1
    I think you have found a MSVS bug/"feature". AFAIK you cannot specialize a template with a different class type (going from `struct` to `union`) Both g++ and clang fail to compile: https://godbolt.org/g/3VDzPM – NathanOliver Aug 03 '18 at 21:41
  • @NathanOliver: funny thing, g++ complains about something else here (partial specialization being a `union` instead of `struct`). If you pass `-fpermissive`, the code compiles (with a warning). – joe_chip Aug 03 '18 at 21:52
  • Do you really need `x` member instead of getter `T& x() { return data[0]; }` ? – Jarod42 Aug 03 '18 at 23:05

2 Answers2

4

This code is not legal. From [temp.class]:

In a redeclaration, partial specialization, explicit specialization or explicit instantiation of a class template, the class-key shall agree in kind with the original class template declaration ([dcl.type.elab]).

A class-key is one of class, struct, or union.

In your case, your partial specialization is illegal, since you use a class-key of union when you previously used struct.


To get the behavior you want, use an anonymous union inside the class:

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; };
    };
};

However, be careful of this union; you may be tempted to access the inactive member, but that's undefined behavior unless the union members share a common initial sequence. I'm not sure in this case if they do, but I think they do not, since std::array is a distinct type from T[2], and I'm not even sure if T[2] and T x, y would be a common initial sequence.

Justin
  • 24,288
  • 12
  • 92
  • 142
0

Your partial specialization is not a union.

As you point out, union cannot be used as a base class, and as Justin points out, using union keyword for partial specialization is not legal.

Adding to this: for some reason MSVC doesn't mind use of union keyword and simply ignores class key of the partial specialization and treats it as a definition of struct.

The same thing happens in case of gcc. It complains about different class-key, but once you pass -fpermissive flag to the compiler, your example compiles, although vector<T, 2> is a structure, not a union.

Demo

joe_chip
  • 2,468
  • 1
  • 12
  • 23