член, определенный в анонимной структуре в защищенном анонимном объединении, по-прежнему общедоступен

Мне удалось скомпилировать и запустить код c++, хотя этого делать не следовало.

Следующий фрагмент не должен компилироваться:

template<typename T, size_t SIZE>
struct Vector {
    Vector(std::initializer_list<T> data) {
        std::copy(data.begin(), data.end(), this->data);
    }

    Vector(T(&data)[SIZE]) {
        std::copy(data, data + SIZE, this->data);
    }

protected:
#pragma pack(push, 1) //stores the alignment of aggregate types and sets it to 1 byte
    union {
        struct {
            T x, y, z, w;
        };
        T data[SIZE];
    };
#pragma pack(pop) //restore old data alignment
};

template<typename T>
struct Vector2 : public Vector<T, 2> {
    using Vector<T, 2>::Vector<T, 2>;

    Vector2(T x = 0, T y = 0) :
        Vector({ x, y }){}

    Vector2(const Vector& vec) :
        Vector(vec) {}

    using Vector::x;
    using Vector::y;
};

int main() {
    double floats[2]{ 2, 3 };
    Vector2<double> v{ floats };
    Vector<double, 2> c{ 5., 6. };

    std::cout << "v.x = " << v.x;
    //Is oke, v.x is visible here because of the public using statement

    std::cout << " c.x = " << c.x << "\n";
    //Is not oke, c is not a Vector2<double>. It is a Vector<double, 2> so its member x is protected and thus not visible from here.
}

вывод: v.x = 2 c.x = 5

Таким образом, эта программа не только успешно компилируется и компонуется, но также запускается и печатает разумные данные. Я попытался изменить тип c на Vector<double, 3>, но это ничего не изменило. Кроме того, участники z и w также видны, как и x и y. Однако data не отображается (например, std::cout << c.data[0]; не будет компилироваться должным образом).

В этом случае Intellisense умнее компилятора, так как успешно обнаруживает ошибку и жалуется на нее.

Я использую Visual Studio 2013.

ПС:

Дополнительный вопрос: я обнаружил еще одну особенность компилятора в этом же фрагменте кода. Если я изменю следующую строку:

using Vector<T, 2>::Vector<T, 2>;

to:

using Vector<T, 2>::Vector;

Я получаю эту ошибку компилятора: error C2886: 'Vector<T,0x02>' : symbol cannot be used in a member using-declaration

Если я изменю его на:

using Vector::Vector;

Компилятор вылетает вместе с: fatal error C1001: An internal error has occurred in the compiler. see reference to class template instantiation 'Vector2<T>' being compiled.

Это (например, тот факт, что он падает), вероятно, просто ошибка в компиляторе, но, если кто-нибудь знает, я все же хотел бы знать, почему ни одна из двух альтернативных форм этой строки не компилируется.


person Jupiter    schedule 18.11.2015    source источник


Ответы (1)


Мне пришлось внести некоторые изменения, чтобы код вообще компилировался на clang. Кажется, что визуальный С++ чрезвычайно разрешителен и допускает незаконный (или, я должен сказать, нестандартный) синтаксис.

Вот исправленная программа:

#include <iostream>
#include <algorithm>

template<typename T, size_t SIZE>
struct Vector {
    Vector(std::initializer_list<T> data) {
        std::copy(data.begin(), data.end(), this->data);
    }

    Vector(T(&data)[SIZE]) {
        std::copy(data, data + SIZE, this->data);
    }

protected:
#pragma pack(push, 1) //stores the alignment of aggregate types and sets it to 1 byte
    union {
        struct {
            T x, y, z, w;
        };
        T data[SIZE];
    };
#pragma pack(pop) //restore old data alignment
};

template<typename T>
struct Vector2 : public Vector<T, 2> {
    using Vector<T, 2>::Vector;

    Vector2(T x = 0, T y = 0) :
    Vector<T, 2>({ x, y }){}

    Vector2(const Vector2& vec) :
    Vector<T, 2>(vec) {}

    using Vector<T, 2>::x;
    using Vector<T, 2>::y;
};

int main() {
    double floats[2]{ 2, 3 };
    Vector2<double> v{ floats };
    Vector<double, 2> c{ 5., 6. };

    std::cout << "v.x = " << v.x;
    //Is oke, v.x is visible here because of the public using statement

    std::cout << " c.x = " << c.x << "\n";
    //Is not oke, c is not a Vector2<double>. It is a Vector<double, 2> so its member x is protected and thus not visible from here.
}

Вот (ожидаемая) ошибка после модификации:

./vec.cpp:66:33: error: 'x' is a protected member of 'Vector<double, 2>'
    std::cout << " c.x = " << c.x << "\n";
                                ^
./vec.cpp:37:15: note: declared protected here
            T x, y, z, w;
              ^
1 error generated.
person Richard Hodges    schedule 18.11.2015