看看这个例子:
struct s77 {
char d[77];
};
struct s1 {
char d;
};
struct Foo: s77, s1 {
};
struct Off {
static const int v = std::size_t(static_cast<s1*>(static_cast<Foo*>(nullptr)+1)) - std::size_t(static_cast<Foo*>(nullptr)+1);
};
此代码尝试将s1
中Foo
的偏移量放入Off::v
。此代码使用GCC / clang进行编译(没有任何警告),但无法使用VS2015 / VS2017进行编译(错误C2131:表达式未评估为常量)
哪种编译器正确?
我能否以符合标准的方式实现此功能?如果不可能,是否可以创建一个适用于VS2015 / VS2017的工作解决方案?我愿意接受任何有效的解决方案,即使根据标准有未定义的行为(但恰好与VS2015和VS2017一起工作)。 Off::v
必须是编译时常量。
我原来的问题是:我有一个tuple
的自己的实现,它是用多重继承实现的(比如clang的tuple
)。我想为元组创建一个编译时常量“描述符”,它包含元组中所有成员的偏移量。该描述符也包含每个元组成员的函数指针。如果我手动创建这个描述符,它看起来像这样(例如):
struct Entry {
int offset;
void (*function)(void *member);
};
Entry descriptor[] = {
{ 0, &SomeType1::static_function },
{ 12, &SomeType2::static_function },
{ 20, &SomeType3::static_function }
};
这样做的目的是我可以有一个通用函数(不是模板),它可以使用这个描述符在每个元组成员上调用特定于类型的函数:
void call(void *tuple, const Entry *entries, int n) {
for (int i=0; i<n; i++) {
entries[i].function(static_cast<char *>(tuple)+entries[i].offset);
}
}
(此解决方案而不是模板call
函数的原因是call
实际上是我的实际代码中的一个巨大功能,并且entry[i].function
调用无法从中计算出来。我想避免大量的代码重复。)
答案 0 :(得分:0)
如下:
struct Entry {
void* (*data_member_getter)(void*);
void (*function)(void *member);
};
namespace details
{
template <std::size_t I, typename Tuple>
constexpr void* voidPGetter(void* tuple)
{
return &std::get<I>(*reinterpret_cast<Tuple*>(tuple));
}
template <typename Tuple, std::size_t I>
constexpr MakeEntry()
{
using type = std::tuple_element_t<I, Tuple>;
return { &voidPGetter<I, Tuple>, &type::static_function };
}
template <typename Tuple, std::size_t ... Is>
constexpr std::array<Entry, sizeof...(Is)>
ComputeEntryHelper(std::index_sequence<Is...>)
{
return {{MakeEntry<Is, Tuple>()...}};
}
}
template <typename Tuple>
constexpt auto ComputeEntry()
{
constexpr auto size = std::tuple_size<Tuple>::value;
return details::ComputeEntryHelper(std::make_index_sequence<size>());
}
然后
void call(void* tuple, const Entry* entries, int n) {
for (int i = 0; i != n; ++i) {
entries[i].function(entries[i].data_member_getter(tuple));
}
}
因此,而不是偏移,具有获取数据的功能。