【发布时间】:2017-09-20 16:34:19
【问题描述】:
看这个例子:
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调用不能从中分解出来。我想避免大量代码重复。)
【问题讨论】:
-
由于您的类型没有en.cppreference.com/w/cpp/concept/StandardLayoutType,我非常怀疑您是否可以在不进入未定义行为领域的情况下计算任何偏移量。
-
@Jodocus:没问题,正如我在问题中所说,如果代码恰好可以工作,UB 在这种情况下很好。
-
考虑使用指向成员的指针而不是偏移量。
标签: c++