【发布时间】:2020-05-08 08:33:12
【问题描述】:
考虑下面的代码
#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;
}
它创建了一个带有数据成员value 的模板化结构base,以及一个继承自它的几个特化的结构derived。我想根据运行时提供的索引访问一个或另一个基类的value。提供的代码似乎没有实现这一点,并且总是返回第一个base 的value。
我想实现它:
- 不改变
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;
}
问题:为什么当前的技巧不起作用,有没有办法让它起作用?
编辑:似乎是 GCC 错误。我报告了它here。与clanghere比较。
额外问题(致语言律师):这是 GCC 错误,还是根据 C++17 标准未定义的行为?
【问题讨论】:
-
GCC 和 Clang 之间的行为 differs。
-
我认为the standard 很清楚这应该可行,所以我投票给 GCC 错误。
-
我在这里报告了这个错误:gcc.gnu.org/bugzilla/show_bug.cgi?id=95004
标签: c++ inheritance c++17 language-lawyer pointer-to-member