【问题标题】:Enforce compile-time constexpr [duplicate]强制编译时 constexpr [重复]
【发布时间】:2013-07-13 21:03:41
【问题描述】:

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

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

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

【问题讨论】:

  • 你可以随时把它变成函数模板:template<int x> int foo() { return x + 1; }
  • 请注意,constexpr 被部分调用是为了抵消您将在此处的答案中看到的所有语法变通方法。
  • #define foo(N) foo<N>() 在我看来是可行的。
  • 另外,在未评估的上下文中,#define REQUIRE_CEXPR(E) []{ constexpr auto x = E; return x; }(),您可以说foo(REQUIRE_CEXPR(1 + 2)) (C++14)。对于 C++11,您可以使用 []()->typename std::decay<decltype((E))>::type 来显式指定类型。虽然更丑:)
  • 无答案:将结果存储在constexpr

标签: c++ c++11 constexpr


【解决方案1】:

用元函数替换它:

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

用法:

foo<12>::value

【讨论】:

  • 或者更好的是,给它一个operator(),这样就类似于一个函数调用。
  • @rubenvb:更好的是,使用变量模板:template &lt;int N&gt; int bar = foo&lt;N&gt;::value;。用法:bar&lt;12&gt;。在 C++14 中可用。
【解决方案2】:

我会使用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

【讨论】:

  • 我没有带有constexpr 的编译器ATM,但是这个想法不会扩展到将static_assert 直接放入foo 中吗?例如。 constexpr int foo(int x) { static_assert(x == x, "Not Static"); return x+1; }
  • @ThomasEding。你可以,但是你会失去使用与运行时评估函数相同的函数的灵活性。由于static_assert 在编译时检查它也不会影响运行时。
【解决方案3】:

不幸的是,除非绝对必要,否则无法保证编译器会评估 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 */

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

【讨论】:

    【解决方案4】:

    是的,它现在可以在纯粹的惯用 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 个最相关的编译器中的 this godbolt.org demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-19
      • 2012-02-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-03
      • 1970-01-01
      相关资源
      最近更新 更多