在 C++ 中对复杂表达式的一部分强制执行 constexpr 的标准方法?

问题描述

有时需要在编译时强制计算某些表达式。

例如如果我们有 f(/*some args*/) 函数是 constexpr,它可以在编译和运行时计算。但是如果我们想强制它在编译时,一种方法是将它的值赋给 constexpr 常量:

constexpr auto x = f(/*some args*/);

但是如果我们希望它被用作复杂表达式的一部分怎么办,整个表达式可以是运行时值,但有时在编译时计算表达式的某些部分如果它提供一些显着的性能是很有趣的改进(或出于下文所述的其他原因)。例如。表达:

int x = 123;
int y = x + 456 * f(/*some args*/);

在上面的表达式中,强制执行 f 编译时计算的一种方法是使用 std::integral_constant

int x = 123;
int y = x + 456 * std::integral_constant<int,f(/*some args*/)>::value;

但也许在标准 C++ 中有一些更短的方法来做到这一点?例如。也许有一种 constexpr 运算符:456 * constexpr(f(/*some args*/))

我想出的最短形式:

template <auto V>
constexpr inline auto ce = V;


int y = x + 456 * ce<f(/*some args*/)>;

这个解决方案很好,但也许标准 C++ 库中已经有类似于 ce<...> 的模板常量?所以如果有一些标准的类/函数,我就不会发明新的类/函数。因为当前的标准类 std::integral_constant 需要指定类型作为第一个参数,还需要 ::value,这不是很短的写法。

为什么我要为强制编译时间而烦恼?由于下一个代码:

Try it online!

struct S {
    consteval bool has42() const {
        return i == 42;
    }
    int i = 0;
};

template <auto V>
constexpr inline auto ce = V;

int main() {
    constexpr S s;
    int z = 10;
    auto x = z + int(ce<s.has42()>); // OK
    auto y = z + int(s.has42()); // Compile error
}

上面的代码在 CLang 下工作得很好,但在最新的 MSVC 行下,auto y.... 编译不正确,错误 error C7595: 'S::has42': call to immediate function is not a constant expression。由于使用了强制编译时间计算的 auto x.....,因此带有 ce<...> 的行在 CLang/MSVC 上都能正确编译。

似乎 MSVC 假定所有表达式都是运行时值,如果它们没有明确声明为 constexpr。当然,尽管它们被标记为运行时值,但编译器仍会进行所有优化,并且编译时代码可能与运行时没有区别。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)