标签: constexpr

通过引用调用`constexpr`成员函数-clang vs gcc

考虑以下示例(代码段 (0)):

struct X
{
    constexpr int get() const { return 0; }
};

void foo(const X& x)
{
    constexpr int i = x.get();
}

int main()
{
    foo(X{});
}
Run Code Online (Sandbox Code Playgroud)

与所有版本上面的例子编译g++之前g++ 10.x,从来没有下编译clang++。错误信息是:

error: 'x' is not a constant expression
    8 |     constexpr int i = x.get();
      |
Run Code Online (Sandbox Code Playgroud)

Godbolt.org 上的现场示例

错误是有道理的,因为x在 的主体中从来不是一个常量表达式foo,但是:

  • X::get()被标记constexpr并且它不依赖于的状态x

  • 更改const X&const X使用每个编译器(在 Godbolt.org 上) 片段 …

c++ language-lawyer constexpr c++17 c++20

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

`constexpr` 函数的 `noexcept` 行为

[expr.unary.noexcept]的措辞在C++17 中发生了变化。


以前(n4140, 5.3.7 noexcept operator [expr.unary.noexcept]),我的重点是

  1. 如果在潜在求值的上下文中表达式将包含,则 noexcept 运算符的结果为 false

    (3.1) 对不具有非抛出异常规范 ([except.spec]) 的函数、成员函数、函数指针或成员函数指针的潜在求值调用,除非调用是常量表达式 ([ expr.const]) ...


现在17.6.2.6 noexcept 运算符 [expr.unary.noexcept]):

  1. 除非表达式可能抛出异常 ([except.spec]),否则noexcept 运算符的结果为

然后在14.5 异常规范 [except.spec] 中

  1. 如果函数声明没有 noexcept 说明符,则该声明具有潜在的抛出异常说明,除非...

但是14.5(3)的除非列表未列出constexpr,因此可能会抛出...

1 LF 在评论中添加的指向 C++17 n4659的链接。


测试代码

constexpr int f(int i) { return i; }

std::cout << boolalpha << noexcept(f(7)) << std::endl;
int a = 7;
std::cout …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer noexcept constexpr c++17

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

为什么 std::isnan 不是 constexpr?

从 C++20 开始,std::isnan 不是 constexpr。

这有技术原因吗?

我能想到的只是它在“C 头文件”中,所以没有人费心去修复它(<limits>处理浮点数的函数是 constexpr,但不幸的numeric_limits是不包含 isnan 检查)。

c++ constexpr c++20

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

未捕获 constexpr 变量

以下代码不能在 clang 中编译(在 GCC 中可以):

struct A{
    int a;
};

auto test(){
    constexpr A x{10};
    return []{
        return x; // <-- here x is A: clang doesn't compile
    }();
}
Run Code Online (Sandbox Code Playgroud)

Clang 的错误是变量 'x' 不能在没有指定捕获默认值的 lambda 中隐式捕获,但我认为 constexpr 变量总是被捕获。

如果 x 是 int,则代码编译:

auto test(){
    constexpr int x{10};
    return []{
        return x; // <-- here x is int: clang is ok
    }();
}
Run Code Online (Sandbox Code Playgroud)

有趣的是,以下代码也可以编译:

auto test(){
    constexpr A x{10};
    return []{
        return x.a;
    }();
}
Run Code Online (Sandbox Code Playgroud)

叮当正确吗?如果是这样,理由是什么?我正在使用 -std=c++17

- 编辑 …

c++ lambda constexpr clang++ c++17

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

为什么 `constexpr` 函数可以在编译和运行时产生不同的结果?

我的一位同事向我展示了这个令人震惊的 C++20 程序:

#include <iostream>

constexpr int p(auto) { return 0; }
constexpr int q() { return p(0); }
constexpr int p(auto) requires true { return 1; }

static_assert(p(0) == 1);
static_assert(q() == 0);

int main()
{
    std::cout << q() << p(0) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

由于错误,GCC 无法构建它:

Error: symbol `_Z1pIiEiT_' is already defined
Run Code Online (Sandbox Code Playgroud)

Clang 成功构建程序并打印11https://gcc.godbolt.org/z/1Gf5vj5oo)。所以static_assert(q() == 0)被成功检查,但std::cout << q()仍然打印1. 怎么会这样?

Visual Studio 2019 16.10.4 的行为更加怪异。在 Release 配置中它也打印11,在 Debug …

c++ language-lawyer constexpr c++-concepts c++20

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

非 constexpr 调用的 constexpr 结果

最近,我很惊讶以下代码也在 clang、gcc 和 msvc 中编译(至少在它们当前的版本中)。

struct A {
    static const int value = 42;
};

constexpr int f(A a) { return a.value; }

void g() {
    A a;  // Intentionally non-constexpr.
    constexpr int kInt = f(a);
}
Run Code Online (Sandbox Code Playgroud)

我的理解是,调用f不是 constexpr 因为参数i不是,但看来我错了。这是适当的标准支持的代码还是某种编译器扩展?

c++ constexpr c++11 constexpr-function

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

鉴于 C++23 对 constexpr 的放宽,constexpr 不能成为默认值吗?

关键字constexpr在引入 C++11 标准时对其函数实施了相当严格的限制。C++14 和 C++20 放宽了这些限制(最值得注意):

  • C++14 允许多个return语句static_assert等。
  • C++20 允许try并且asm

C++23 进一步软化了这些限制。从我在cppreference中看到的,constexprfor函数似乎只剩下以下含义:

  • 它不能是协程
  • 对于构造函数和析构函数,该类必须没有虚拟基类
  • 对于 constexpr 函数模板和类模板的 constexpr 成员函数,至少一种特化必须满足上述要求。

C++23 甚至删除了 constexpr 函数必须在编译时对于p2448r2中的任何类型“可计算”的限制。根据我的理解,这完全消除了constexpr在编译时评估函数的想法。

是这样吗?如果是这样,constexpr函数还有什么用处呢?

c++ language-design constexpr constexpr-function c++23

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

可以在 constexpr 函数中声明静态局部变量吗?

可以在函数中使用static局部变量吗?constexpr例如:

#include <string_view>
#include <utility>

enum class axis {
    x, y, z
};

constexpr std::string_view axis_name(axis a) {
    // use static constexpr to avoid putting the table onto the stack
    static constexpr std::string_view names[] {
        "x", "y", "z"
    };
    return names[std::to_underlying(a)];
}

constexpr auto x_name = axis_name(axis::x);
Run Code Online (Sandbox Code Playgroud)

GCC 12 无法编译此错误:

<source>:9:39: error: 'names' defined 'static' in 'constexpr' context
    9 |     static constexpr std::string_view names[] {
      |                                       ^~~~~
Run Code Online (Sandbox Code Playgroud)

其他编译器允许它。规则是什么?什么时候允许?

  • 我们可以static一般使用,或者
  • 只是static const,或者
  • 只是 …

c++ constants constexpr c++23

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

std::initializer_list 什么时候可以是 constexpr?

根据 cppreference.com,std::initializer_lists 具有constexpr 构造函数constexpr 大小方法(C++14 起)。

尽管我使用的编译器似乎同意 constexpr 初始值设定项列表的大小确实是 constexpr,但在某些情况下,它不相信我的列表是 constexpr。由于 std::initializer_lists 可能涉及一些“编译器魔法”,我开始想知道 constexpr 是否不适用于它们,其方式与适用于非魔法对象的方式完全相同。

我跳到 Compiler Explorer 上,发现主要编译器在这个主题上并不一致

那么以下四种情况的正确行为(根据标准)是什么?

#include <initializer_list>

using size_type = std::initializer_list<int>::size_type;

template <typename T>
size_type Foo(std::initializer_list<T> const &list) {
    return list.size();
}

int main() {
    // 1.  Example based on
    // https://en.cppreference.com/w/cpp/utility/initializer_list/size
    // gcc: works
    // clang: no viable c'tor or deduction guide
    // msvc: works
    static_assert(std::initializer_list{1, 2, 3}.size() == 3);

    // 2.  Make a constexpr std::initializer_list<T> with T …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer constexpr stdinitializerlist c++20

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

可以将具有未初始化字段的对象安全地添加到 std::vector 中吗?

在以下程序中,struct 的默认构造函数A不会初始化其字段v。然后在常量表达式中,std::vector<A>放置有A()对象:

#include <vector>

struct A {
  constexpr A() noexcept {}
  int v;
};

constexpr bool f() {
    std::vector<A> as;
    as.reserve(1);
    as.emplace_back();
    return true;
}
static_assert( f() );
Run Code Online (Sandbox Code Playgroud)

MSVC 编译器抱怨读取未初始化的变量:

<source>(14): error C2131: expression did not evaluate to a constant
<source>(11): note: failure was caused by a read of an uninitialized symbol
<source>(11): note: see usage of 'A::v'
Run Code Online (Sandbox Code Playgroud)

但 GCC 和 Clang 都对该程序很满意。在线演示: https: //godbolt.org/z/addx11aTT

这里哪个编译器是正确的?

c++ vector language-lawyer constexpr

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