标签: consteval

保持函数参数的保守性

我正在使用整洁的 fmt 库,该库在其版本 8 中会在编译时检查其格式字符串(如果编译器支持相关功能)。

在某些时候,我想编写以下代码:

throw my_exception("error: {}", 123);
Run Code Online (Sandbox Code Playgroud)

可悲的是,天真的实现:

struct my_exception : std::runtime_error {
  template<typename... Args>
  my_exception(Args&&... args)
    : std::runtime_error{fmt::format(std::forward<Args>(args)...)} 
  { }
};
Run Code Online (Sandbox Code Playgroud)

失败,因为这会失去字符串文字参数的“consteval-ness”,这是fmt::format. 目前,我决定以下几点:

template<std::size_t N>
struct literal {
  constexpr literal(const char (&str)[N]) noexcept {
    std::copy_n(str, N, this->str);
  }

  char str[N];
};

template<literal lit>
struct exception : std::runtime_error {
  template<typename... Args>
  exception(Args&&... args)
    : std::runtime_error{fmt::format(lit.str, std::forward<Args>(args)...)}
  {

  }
};
Run Code Online (Sandbox Code Playgroud)

被称为像

throw my_exception<"foo {}">(123);
Run Code Online (Sandbox Code Playgroud)

如何在保持编译时检查的同时恢复正常的函数调用语法?

c++ constexpr c++20 fmt consteval

3
推荐指数
1
解决办法
680
查看次数

C++20 consteval 函数和 constexpr 变量 - 是否保证在编译时计算它们?

在 C++20 中,我们有consteval声明立即函数的关键字。例如:

consteval int f(int x) { return x * x; }
Run Code Online (Sandbox Code Playgroud)

需要这样的函数来生成常量表达式。但是,根据标准,常量表达式不需要在编译时实际求值,除非它用在需要常量的地方,例如在模板参数中。例如,标准中似乎没有任何内容要求在编译时对其进行评估:

int a = f(10);
Run Code Online (Sandbox Code Playgroud)

然而,这些要求强烈表明立即函数应该在编译时进行评估。

标准中似乎也没有要求在编译时评估 constexpr 变量。所以即使我们创建变量constexpr,即

constexpr int a = f(10);
Run Code Online (Sandbox Code Playgroud)

它只断言这f(10)是一个常量表达式并生成a一个常量表达式(但同样,常量表达式不需要在编译时实际评估它们)。然而,就像以前一样,对 constexpr 变量的要求强烈表明它们应该在编译时进行评估。

只有constinit 变量的定义不同 - constinit 变量需要进行静态初始化,因此必须在编译时计算它们并直接嵌入到二进制文件中。然而,这个相关问题的答案说 constexpr 意味着 constinit,至少对于全局变量来说,这似乎与我上面写的内容相矛盾。

那么, consteval 函数和 constexpr 变量是否保证在编译时进行求值?


旁注:我的实际用例涉及尝试使用常量初始化结构中的字段,如下所示:

consteval int my_complicated_calculation() {
    // do complicated mathematics and return an int
}
struct A {
    int value;
    A() : value{my_complicated_calculation()} {}
}
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer constexpr c++20 consteval

3
推荐指数
1
解决办法
1417
查看次数

使用 constexpr 代替 consteval 函数有哪些优点?

这可能看起来与使用 consteval 而不是 constexpr 函数的优点是什么相同的问题? 但实际上恰恰相反:

现在我们有了 C++20 consteval,在什么(现实)场景中我仍然需要/创建 constexpr 函数而不是 consteval 函数(或普通函数)?

我知道 constexpr 函数也可以使用在运行时评估的参数来调用,这与 consteval 函数不同(请参阅示例代码中的 ***),但为什么我需要它呢?我的意思是我也可以使用普通函数。

int FunNormal()
{
    return 12345;
}    

consteval int FunConstEval(int p)
{
    return p+3;
}    

constexpr int FunConstExpr(int p)
{
    return p+3;
}    
    

int main() 
{
    // FunConstEval(FunNormal());               // illegal
    FunConstExpr(FunNormal());                  // legal, but why would I ever want to do this? ***
    
//    constexpr int a1 = FunNormal();           // illegal, obviously
//    constexpr int a1 = FunConstExpr(FunNormal());     // illegal
    constexpr …
Run Code Online (Sandbox Code Playgroud)

c++ c++20 consteval

1
推荐指数
1
解决办法
285
查看次数

来自不同翻译单元的约束函数可以干扰吗?

我试图探究某个功能的含义,inline并偶然发现了这个问题。考虑这个小程序(demo):

/* ---------- main.cpp ---------- */
void other();

constexpr int get()
{
    return 3;
}

int main() 
{
    std::cout << get() << std::endl;
    other();
}

/* ---------- other.cpp ---------- */
constexpr int get()
{
    return 4;
}

void other()
{
    std::cout << get() << std::endl;
}

Run Code Online (Sandbox Code Playgroud)

在不进行优化的情况下进行编译时,该程序将产生以下输出:

3
3
Run Code Online (Sandbox Code Playgroud)

可能不是我们想要的,但是至少我可以解释一下。

  1. 不需要编译器constexpr在编译时计算函数结果,因此决定将其推迟到运行时。
  2. constexpr 在功能上意味着 inline
  3. 我们的get()功能碰巧有不同的实现
  4. 我们没有将get()函数声明为静态
  5. 链接器只能选择该get()功能的一种实现

碰巧的是,链接器get()从中选择main.cpp,返回了3。

现在到我不了解的部分。我只是get()功能从更改constexpr为 …

c++ one-definition-rule constexpr c++20 consteval

0
推荐指数
2
解决办法
93
查看次数

变量上的 consteval 与 constexpr

有什么区别constexprconsteval

 consteval int x1 = 2;
 constexpr int x2 = 5;
Run Code Online (Sandbox Code Playgroud)

使用 constexpr 比使用 consteval 更好吗?

c++ constexpr c++11 c++20 consteval

0
推荐指数
1
解决办法
518
查看次数