【发布时间】:2021-11-17 20:51:52
【问题描述】:
我希望有一个在 constexpr 上下文中使用时行为不同的类型。
看这个例子:
#include <cstdio>
#include <type_traits>
template <bool IS_CONSTANT_EVAL>
struct Bar;
template <>
struct Bar<false> {
constexpr int doIt() const {
return 0;
}
};
template <>
struct Bar<true> {
constexpr int doIt() const {
return 1;
}
};
constexpr int foo() {
if (std::is_constant_evaluated()) {
Bar<true> v;
return v.doIt();
} else {
Bar<false> v;
return v.doIt();
}
}
int main() {
int rt = foo();
constexpr int ce = foo();
printf("Runtime: %d ConstEval: %d \n", rt, ce);
}
在此示例中,foo 无论是从 constexpr 上下文中调用,其行为都会有所不同,因为特化依赖于 constexpr-ness,因此它会打印:
Runtime: 0 ConstEval: 1
但如果我尝试将其简化为:
constexpr int foo() {
Bar<std::is_constant_evaluated()> v;
return v.doIt();
}
它不再起作用了,因为std::is_constant_evaluated() 总是返回true 作为模板参数。
甚至,我想要一个更简单的foo,像这样:
constexpr int foo() {
Bar v;
return v.doIt();
}
所以Bar 本身应该以某种方式处理 constexpr-ness,我不想在每次使用 Bar 时重复 std::is_constant_evaluated()。
可以这样做吗?
注意:我实际上不想有不同的行为,只是不同的实现。由于 constexpr 的限制,我需要根据 constexpr-ness 对 Bar 进行不同的实现。例如,memcpy 和 reinterpret_cast 使表达式不是常量。因此,如果Bar 用于常量表达式,我需要使用一些与 constexpr 兼容的技术来替换memcpy 或reinterpret_cast。
注意 2:我确实需要不同的 Bar 定义,不仅仅是 doIt 需要不同。如果在常量表达式中使用memcpy 和reinterpret_cast,则替换Bar 需要额外的成员。
【问题讨论】:
-
从
Bar::doIt()中的示例if (std::is_constant_evaluated())应该可以完成这项工作,不是吗? Demo -
为什么不在
Bar实现中检查std::is_constant_evaluated()是否有需要这种实现分支的函数? -
我重写了您的示例,这样您就无需在每次使用
Bar时为std::is_constant_evaluated()烦恼:See here。但这不是不同的实现,只是不同的行为。但是您在问题中的示例不需要不同的实现即可工作。也许如果你能给我们一个你真正想做的真实例子,就会更容易理解你的问题/需求。 -
@Fareanor:因为
Bar在常量表达式中使用时需要一些额外的成员,所以不同的不仅仅是函数实现。 -
难道你不能拥有那些额外的成员,并且只有当
if(std::is_constant_evaluated())是true时才使用它们?如果您不介意额外的空间浪费,以防万一。
标签: c++