Рассмотрим следующий код
#include <array>
#include <iostream>
template <std::size_t> struct base {
std::size_t value;
};
struct derived: base<0>, base<1> {
using pointer_type = std::size_t derived::*;
static constexpr std::array<pointer_type, 2> members{{
&derived::base<0>::value,
&derived::base<1>::value
}};
constexpr std::size_t& operator[](std::size_t i) noexcept {
return this->*(members[i]);
}
constexpr const std::size_t& operator[](std::size_t i) const noexcept {
return this->*(members[i]);
}
};
int main(int, char**) {
derived x{42, 84};
std::cout << sizeof(base<0>) + sizeof(base<1>) << " " << sizeof(derived);
std::cout << std::endl;
std::cout << x[0] << " " << x[1];
std::cout << std::endl;
return 0;
}
Он создает шаблонную структуру base
с элементом данных value
и структуру derived
, которая наследуется от нескольких его специализаций. Я хотел бы получить доступ к value
одного или другого базового класса в зависимости от индекса, предоставленного во время выполнения. Предоставленный код, похоже, не обеспечивает этого и всегда возвращает value
первого base
.
Я бы хотел добиться этого:
- Без изменения кода из
base
- Без изменения способа
derived
наследуется от base
- Без изменения
sizeof(derived)
(трюки должны быть constexpr/static
) - Только с использованием определенного поведения (например, без неопределенного поведения
reinterpret_cast
) - Доступ должен быть
O(1)
сложностью
Другими словами, макет кода, который я хотел бы чтобы не менять, должно быть:
#include <array>
#include <iostream>
template <std::size_t> struct base {
std::size_t value;
};
struct derived: base<0>, base<1> {
/* things can be added here */
constexpr std::size_t& operator[](std::size_t i) noexcept {
/* things can be added here */
}
constexpr const std::size_t& operator[](std::size_t i) const noexcept {
/* things can be added here */
}
};
int main(int, char**) {
derived x{42, 84};
std::cout << sizeof(base<0>) + sizeof(base<1>) << " " << sizeof(derived);
std::cout << std::endl;
std::cout << x[0] << " " << x[1];
std::cout << std::endl;
return 0;
}
ВОПРОС : Почему текущий трюк не работает, и есть ли способ заставить его работать?
РЕДАКТИРОВАТЬ : похоже, ошибка G CC. Я сообщил об этом здесь . Сравнение с clang здесь .
ДОПОЛНИТЕЛЬНЫЙ ВОПРОС (к языковым юристам) : это ошибка G CC или неопределенное поведение в соответствии с C + +17 стандарт?