标签: constexpr

std::mutex 的 constexpr 构造函数是如何实现的?

在查看 C++ Reference for 时std::mutex,我注意到 for 的构造函数std::mutex被标记为constexpr

起初这令人惊讶,因为我们通常必须进行系统调用(pthread_mutex_init()(POSIX)或CreateMutex()(Windows))来初始化互斥体。然而,经过仔细检查,对于 POSIX,可以使用常量静态PTHREAD_MUTEX_INITIALIZER初始化互斥体(可能作为全局变量),尽管我找不到 Windows 的等效项。

然而,即使 POSIX 的静态初始化是constexpr构造函数背后的原因,但实现中仍然存在各种未解决的问题:

  1. 在 Windows(或许还有其他非 POSIX 系统)上,可能没有静态初始化互斥体的方法。
  2. 在添加C++20 之前,不可能根据编译时是否调用构造函数来拥有不同的代码路径std::is_constant_evaluated(),因此我们没有办法确定是否应该使用PTHREAD_MUTEX_INITIALIZER或。pthread_mutex_init()

那么,如何实现 的constexpr构造函数呢std::mutex

c++ constructor mutex constexpr c++11

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

如果传递的初始化列表映射为符号 (constexpr),MSVC 上的 constexpr std::max 会失败

背景

为多个平台构建的大型 C++17 项目。必须支持 MSVC、clang 和 gcc

问题

以下代码在 MSCV 上失败,但对于其他编译器来说没问题。

#include <algorithm>
#include <initializer_list>

#define FOO_1 1
#define FOO_2 2
#define FOO_3 3

class Baz {
  static constexpr auto data = {FOO_1, FOO_2, FOO_3};
  static constexpr auto copy_max = std::max({FOO_1, FOO_2, FOO_3});
  static constexpr auto data_max = std::max(data);

  void bar(std::initializer_list<int>);

  void test();
};

void Baz::test()
 { bar(data); }
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/7nv3z3rMY

FOO_x宏用于外部库。Baz是我的代码。现在我需要data_max一些逻辑,我希望在编译时计算它。

作为一种解决方法,我引入了copy_max由重复代码初始化的方法,这是不好的(有很多值和列表可以更改),也data可以在运行时代码中使用。

显然问题仅存在于 msvc 19.29(安装在我的机器上)旧版本没有此问题。

问题

有没有一种方法可以在不使用额外的宏或重复代码的情况下以某种方式克服这个问题?我尝试使用std::max_element自 C++17 以来的 …

c++ visual-c++ constexpr c++17

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

如何编写可移植的 constexpr std::copysign()?

特别是,它必须像 NaN 一样工作std::copysign。同样,我需要一个 constexpr std::signbit

constexpr double copysign(double mag, double sgn)
{
    // how?
}

constexpr bool signbit(double arg)
{
    // how?
}

// produce the two types of NaNs
constexpr double nan_pos = copysign(std::numeric_limits<double>::quiet_NaN(), +1);
constexpr double nan_neg = copysign(std::numeric_limits<double>::quiet_NaN(), -1);

// must pass the checks
static_assert(signbit(nan_pos) == false);
static_assert(signbit(nan_neg) == true);
Run Code Online (Sandbox Code Playgroud)

背后的故事是我在编译时需要两种类型的 NaN,以及区分它们的方法。我能想到的最直接的方法是操纵 NaN 的符号位。它在运行时起作用;现在我只想将一些计算移至编译时间,这是最后一个障碍。

注意:目前,我依赖 GCC,因为它有这些函数的内置版本,而且它们确实是constexpr,这很好。但我希望我的代码库能够在 Clang 上编译,或许也可以在其他编译器上编译。

c++ math nan constexpr

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

可以比较 std::type_info 上的指针在常量表达式中是否相等吗?

可以在任何类的对象constexpr上定义一个指针。该语言是否允许在编译时比较此类指针是否相等?std::type_infoT

例如:

#include <typeinfo>

template <typename T>
inline constexpr auto * pType = &typeid(T);

int main() {
    static_assert( pType<int> == pType<int> );
    static_assert( pType<int> != pType<char> );
} 
Run Code Online (Sandbox Code Playgroud)

问题出现了,因为 Clang 接受它,但 GCC 返回错误:

error: non-constant condition for static assertion
    8 |     static_assert( pType<int> != pType<char> );
      |                    ~~~~~~~~~~~^~~~~~~~~~~~~~
<source>:8:31: error: '(((const std::type_info*)(& _ZTIi)) != ((const std::type_info*)(& _ZTIc)))' is not a constant expression
Run Code Online (Sandbox Code Playgroud)

演示: https: //gcc.godbolt.org/z/9broYrEn7

c++ typeid language-lawyer constexpr c++17

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

constexpr 引用必须只能用 C++ 中的静态对象初始化吗?

如果constexpr引用仅使用另一个对象初始化,constexpr如示例所示:

int main() {
    constexpr int a = 0;
    constexpr const int & b = a;
}
Run Code Online (Sandbox Code Playgroud)

然后 GCC 和 Clang 都拒绝了它constexpr variable 'b' must be initialized by a constant expression, address of non-static constexpr variable 'a' may differ on each invocation of the enclosing function; add 'static' to give it a constant address

同时MSVC接受该示例。演示: https: //gcc.godbolt.org/z/Whv7YeWKW

添加到以下内容后,所有编译器都会接受代码static

static constexpr int a = 0;
Run Code Online (Sandbox Code Playgroud)

演示: https: //gcc.godbolt.org/z/abeP4z64E

标准是否真的要求任何constexpr引用只能使用静态对象进行初始化?

c++ language-lawyer constexpr

5
推荐指数
0
解决办法
99
查看次数

常量表达式中指向静态 constexpr 变量的指针的比较

在以下代码中,比较static constexpr变量的指针x和是否不相等:y

int main() {
    static constexpr int x = 1;
    static constexpr int y = 2;
    static_assert( &x != &y );
}
Run Code Online (Sandbox Code Playgroud)

它在 Clang 中工作正常,但在打印的 GCC 中却不行

error: non-constant condition for static assertion
error: '((& x) != (& y))' is not a constant expression
Run Code Online (Sandbox Code Playgroud)

演示: https: //gcc.godbolt.org/z/3WdqP49Gq

这只是 GCC 中的一个错误吗?

c++ language-lawyer constexpr

5
推荐指数
0
解决办法
136
查看次数

“constexpr”函数中对“文字类型”的要求

这是我的代码:

class agg_t1{
    int x;      // private non-static data menber
};
class agg_t2{
    agg_t2(){}      // user-provided constructor
};
constexpr void ce1(agg_t1 arg){};       // OK
constexpr void ce2(agg_t2 arg){};       // ERROR:  parameter type 'agg_t2' is not a literal type 
Run Code Online (Sandbox Code Playgroud)

根据dcl.constexpr

constexpr 函数的定义应满足以下要求: ...

  • 它的每个参数类型都应该是文字类型;...

basic#types.general-10

如果类型是文字类型,则它是: ...

  • 它可以是闭包类型、聚合类型,或者......

我理解为什么agg_t2不是文字类型的原因是,它违反了规则dcl.init.aggr#1.1

聚合是一个数组或一个类......

  • 没有用户声明或继承的构造函数...

我认为agg_t1可能不是文字类型,因为它也违反了规则dcl.init.aggr#1.1

聚合是一个数组或一个类......

  • 没有私有或受保护的直接非静态数据成员...

然而......编译器结果告诉我我对 的假设是错误的agg_t1

我的问题是:

如果agg_t1的私有数据成员x …

c++ language-lawyer constant-expression constexpr constexpr-function

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

为什么 C++ 编译器不使用编译时已知的值来替换对 const 类成员的访问?

在这段代码中,为什么c++编译器在编译时不直接返回1 test(),而是从内存中读取值?

struct Test {
  const int x = 1;

  // Do not allow initializing x with a different value
  Test() {}
};
int test(const Test& t) {
  return t.x; 
}
Run Code Online (Sandbox Code Playgroud)

戈尔螺栓上的代码

编译器输出:

test(Test const&):                         # @test(Test const&)
    mov     eax, dword ptr [rdi]
    ret
Run Code Online (Sandbox Code Playgroud)

我本来期望:

test():                               # @test(Test const&)
    mov     eax, 1
    ret
Run Code Online (Sandbox Code Playgroud)

是否有任何符合标准的方法来修改 的值Test::x以包含与 不同的值1?或者是否允许编译器进行这种优化,但 gcc 和 clang 都没有实现它?

编辑:当然,您立即发现我将其作为最小示例的错误,即允许结构的聚合初始化。我使用空的默认构造函数更新了代码,以防止出现这种情况。(godbolt 上的旧代码

c++ constants compiler-optimization constexpr

5
推荐指数
2
解决办法
306
查看次数

如何在C++中通过reinterpret_cast将非常量变量转换为常量静态整型类成员变量?

我正在读一本关于为微控制器编写现代 C++ 代码的书,书名为“实时 C++”。我正在尝试自己编写书中的代码。然而,在复制书中的代码并尝试构建它时,我收到了以下编译错误:

错误 C2131:表达式未求值为常量。
消息:遇到非常量(子)表达式

我插入了下面代码的相关部分:

#include <cstdint>
#include <iomanip>
#include <iostream>
namespace mcal
{
  namespace reg
  {
    // Simulate the transmit and receive hardware buffers on the PC.
    std::uint8_t dummy_register_tbuf;
    std::uint8_t dummy_register_rbuf;
  }
}

class communication
{
  private:
    static constexpr std::uint8_t* tbuf = reinterpret_cast<std::uint8_t*>(&mcal::reg::dummy_register_tbuf); 
    static constexpr std::uint8_t* rbuf = reinterpret_cast<std::uint8_t*>(&mcal::reg::dummy_register_rbuf);
};

/* rest of the nonrelated code */
Run Code Online (Sandbox Code Playgroud)

该错误指示发生转换的这两行。我知道我们尝试使用 static constexpr 整型类成员变量,因为这可以确保对它们进行优化(不断折叠)。我认为发生错误是因为我们尝试将非常量变量设置为常量变量,但我肯定是错的。因此,我恳请您向我解释一下这里真正的问题是什么以及作者为什么会犯这样的错误(如果这是一个错误)。另外,如果您另外指出正确的铸造方法,我将不胜感激。非常感谢。

c++ reinterpret-cast constexpr

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

引用求值什么时候会使某些东西不是常量表达式?

考虑以下代码片段

struct test1 {
    static constexpr int get()  {
        return 1;
    }
};

struct test2 {
    constexpr int get() const {
        return 1;
    }
};

template <class T>
int get(T&& t) {
    if constexpr (t.get() == 1) {
        return 1;
    }
    return 2;
}

int main() {
    return get(test1{}) + get(test2{});
}
Run Code Online (Sandbox Code Playgroud)

当尝试使用 GCC-11.1 (-std=c++2a) 进行编译时,get模板可以成功编译test1,但不能使用test2. 它们之间唯一的区别是test2::get是静态的。

显然,它不能用 进行编译test2,因为t参数不是“核心常量表达式”,根据7.7 expr.const(5.13)

表达式 e 是核心常量表达式,除非对 e …

c++ reference language-lawyer constexpr c++20

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