强制执行编译时constexpr

Enforce compile-time constexpr

本文关键字:constexpr 编译 强制执行      更新时间:2023-10-16

在C++11中,我们得到constexpr:

constexpr int foo (int x) {
    return x + 1;
}

是否可以将动态值为xfoo调用作为编译时错误?也就是说,我想创建一个foo,这样就只能传入constexpr参数。

用元函数替换它:

template <int x> struct foo { static constexpr int value = x + 1; };

用法:

foo<12>::value

不幸的是,除非绝对必要,否则无法保证constexpr函数,即使是最琐碎的函数,也会被编译器求值。也就是说,除非它出现在编译时需要其值的地方,例如在模板中。为了强制编译器在编译期间进行评估,您可以执行以下操作:

constexpr int foo_implementation (int x) {
    return x + 1;
}
#define foo(x) std::integral_constant<int, foo_implementation(x)>::value

然后像往常一样在代码中使用foo

int f = foo(123);

这种方法的好处是它保证了编译时的评估,如果将运行时变量传递给foo:,则会出现编译错误

int a = 2;
int f = foo(a); /* Error: invalid template argument for 'std::integral_constant',
                   expected compile-time constant expression */

不太好的地方是它需要一个宏,但如果你想要有保证的编译时评估和漂亮的代码,这在目前看来是不可避免的。(不过我很想被证明是错的!)

是的,现在可以在纯惯用C++中完成,因为C++20增加了对这类问题的支持。使用consteval对函数进行注释,可以确保在编译时对其进行求值。https://en.cppreference.com/w/cpp/language/consteval

consteval int foo( int x ) {
    return x + 1;
}
int main( int argc, char *argv[] )
{
    return foo( argc ); // This will not compile
    return foo( 1 );    // This works
}

另请参阅3个最相关的编译器中的godbolt.org演示。

我将使用static_assert,如本例所示

#include<iostream>
constexpr int foo(int x) {
        return x+1;
}
int main() {
        // Works since its static
        std::cout << foo(2) << std::endl;
        static_assert(foo(2) || foo(2) == 0, "Not Static");
        // Throws an compile error
        int in = 3;
        std::cout << foo(in) << std::endl;
        static_assert(foo(in) || foo(in) == 0, "Not Static");
}

有关更多信息:http://en.cppreference.com/w/cpp/language/static_assert