标签: constexpr

constexpr std::string_view::find_last_of 在带有 libstdc++ 9 的 clang 8 上不起作用

以下代码在 g++ 9 下编译,带有标志-std=c++17,但不是带有相同标志的 clang 8:

#include <string_view>
#include <cstdlib>


int main() {

        constexpr std::string_view hello = "hello";
        constexpr size_t last_l = hello.find_last_of("lo");
}
Run Code Online (Sandbox Code Playgroud)

错误信息如下:

test.cpp:8:19: error: constexpr variable 'last_l' must be initialized by a constant expression
        constexpr size_t last_l = hello.find_last_of("lo");
                         ^        ~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/char_traits.h:349:9: note: cast from 'void *' is not allowed in a constant expression
        return static_cast<const char_type*>(__builtin_memchr(__s, __a, __n));
               ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/string_view.tcc:150:12: note: in call to 'find(&"lo"[0], 2, "hello"[4])'
              if (traits_type::find(__str, __n, this->_M_str[__size]))
                  ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/string_view:402:22: note: …
Run Code Online (Sandbox Code Playgroud)

c++ g++ clang constexpr c++17

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

为什么 constexpr 函数对于引用的行为不同?

编译时计数函数参数的启发

考虑这个代码

template <typename... Args>
constexpr int count(Args&&...)
{
    return sizeof...(Args);
}

void foo(int value)
{
    static_assert(count(value) >= 0);  // OK

    const int& ref = 7;
    static_assert(count(ref) >= 0);  // Error
}
Run Code Online (Sandbox Code Playgroud)

首先static_assert工作正常。第二个报错:

<source>:12:19: error: static_assert expression is not an integral constant expression
    static_assert(count(ref) >= 0);
                  ^~~~~~~~~~~~~~~
<source>:12:25: note: initializer of 'ref' is not a constant expression
    static_assert(count(ref) >= 0);
                        ^
<source>:11:16: note: declared here
    const int& ref = 7;
               ^
Run Code Online (Sandbox Code Playgroud)

这两种情况都令我感到惊讶。为什么第一个static_assert工作正常,而 …

c++ constexpr

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

静态成员声明为 const 但初始化为 constexpr

考虑一个具有常量成员的类:

class foo {
public:
    const static int N;
};
Run Code Online (Sandbox Code Playgroud)

foo::N 需要初始化:

constexpr int foo::N = 5;
Run Code Online (Sandbox Code Playgroud)

并注意使用constexpr限定符而不是const这里似乎是一个错误。

但是 GCC、Clang 和 MSVC 都编译得很好!

  • 语言中是否有允许在此处更改限定符的内容?
  • 这是所有三个编译器都忽略的错误吗?

Clang 甚至允许同时使用两个限定符版本:

constexpr int foo::N = 3;
const int foo::N = 5;

int main(){
    return foo::N; //returns 3
}
Run Code Online (Sandbox Code Playgroud)

这是怎么回事?

c++ initialization constexpr c++17

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

比较两个 constexpr 指针不是 constexpr 吗?

我正在寻找一种在编译时将类型映射到数值的方法,理想情况下不使用答案中建议的散列。

由于指针可以constexpr,我试过这个:

struct Base{};
template<typename T> struct instance : public Base{};

template<typename T>
constexpr auto type_instance = instance<T>{};

template<typename T>
constexpr const Base* type_pointer = &type_instance<T>;

constexpr auto x = type_pointer<int> - type_pointer<float>; // not a constant expression
Run Code Online (Sandbox Code Playgroud)

gcc 和 clang 都拒绝此代码,因为type_pointer<int> - type_pointer<float>它不是一个常量表达式,例如,请参见此处

为什么?

我可以理解,从一个编译到下一个编译,这两个值之间的差异不会稳定,但在一个编译中,它应该是constexpr,恕我直言。

c++ pointers constexpr

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

std::max 在统一初始化和 constexpr int 下表现出乎意料

我正在试验 std::max。我想通过统一初始化(花括号)传递整数 constexpr,以将它们与浮点变量进行比较。

实验 a):用 double/int 混合调用 std::max()

    double a = 3.0;
    int b = 5;
    auto res = std::max(a, b);
Run Code Online (Sandbox Code Playgroud)

不编译。铿锵报告error: no matching function for call to 'max'。这当然没问题。

实验 b):使用花括号 + constexpr int 进行非箭头转换

    double a = 3.0;
    constexpr int b = 5;
    auto res = std::max(a, {b});
Run Code Online (Sandbox Code Playgroud)

编译并按预期工作:返回值为 5.0 的双精度值。

实验 c):与 b) 相同,但交换 std::max 的参数。

    double a = 3.0;
    constexpr int b = 5;
    auto res = std::max({b}, a);
Run Code Online (Sandbox Code Playgroud)

不能在 gcc 和 clang 下编译。为什么?

铿锵报告 …

c++ std max constexpr

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

返回从字符串文字创建的静态 string_view 是否安全?

我有一个相对简单的用例:我想将一个特征关联到一个类,该类将返回一些用户定义的字符串,即一些用户定义的注册 ID。由于这个注册应该在编译时定义,我希望它是 constexpr,所以我写了如下内容:

template <typename T>
struct ClassRegistration
{
    static constexpr std::string_view
    Name();
};

template <>                                                                                    
struct ClassRegistration<int>                                                            
{                                                                                              
    static constexpr std::string_view                                                        
    Name()                                                                                     
    {                                                                                          
        return std::string_view{ "int" };                                                     
    }                                                                                          
};
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/5p8xkA

一切正常,但由于 string_view 实际上并不拥有它的缓冲区,我想知道它是否保证安全,我不只是指一个悬空指针。从我读到的字符串文字保证具有与程序本身一样长的生命周期(从这个函数返回的字符串文字的SO Lifetime)。

因此,string_view 的这种用法是否安全合适?

c++ string-literals constexpr string-view c++17

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

GCC 和 Clang 在与 __builtin_constant_p 相关的 static_assert 方面有所不同

我碰巧发现GCC和Clang在以下代码的编译上有所不同:

struct Foo
{
    int mem = 42;
};

int main()
{
    constexpr Foo foo;
    static_assert(__builtin_constant_p(foo));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我用g++ -std=c++17和编译clang++ -std=c++17

特别是,

  • 加++ g++-9 (Homebrew GCC 9.3.0_1) 9.3.0编译,而
  • clang++Apple clang version 11.0.3 (clang-1103.0.32.62)无法编译,抱怨说
error: static_assert failed due to requirement '__builtin_constant_p(foo)'
    static_assert(__builtin_constant_p(foo));
    ^             ~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

我没有发现任何关于__builtin_constant_p.

为了 __builtin_constant_p

海湾合作委员会

您可以使用内置函数 __builtin_constant_p 来确定某个值在编译时是否已知为常量...

叮当

Clang 支持许多与 GCC 语法相同的内置库函数,包括 __builtin_nan、__builtin_constant_p、__builtin_choose_expr、__builtin_types_compatible_p、__builtin_assume_aligned、__sync_fetch_and_add 等。

问题:虽然我知道__builtin_constant_p是一个编译器扩展,但哪个应该是正确的?

c++ g++ static-assert constexpr clang++

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

C++ 编译时调试

在该准则下constexpr everything,随着constevalC++20的引入,越来越多的代码在编译时被评估。

这导致了一个显而易见的问题:我们如何调试它?

目前唯一的提示是编译器错误。但是如果代码编译了,但仍然没有达到预期的效果怎么办。有什么工具可以帮助解决这个问题吗?有没有检查的可能?

一个相关的问题是:如何知道哪些会在编译时真正被“执行”,哪些会在有限定符的情况下保持运行。

c++ compilation constexpr c++20 consteval

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

C++:无法从相同类型的常量初始化枚举值

由于未知原因,我无法从constexpr值初始化枚举值。这是我的代码:

enum class Enum: unsigned int; //Forward declaration

constexpr Enum constant = static_cast<Enum>(2);

enum class Enum: unsigned int {
  A = 0,
  B = 1,
  C = B,                                   //This works
  D = constant,                            //This FAILS
  E = static_cast<unsigned int>(constant), //This works
  F = Enum::B                              //This works
};
Run Code Online (Sandbox Code Playgroud)

我无法理解的是为什么我可以写C = B,但不能写D = constantB并且constant具有相同的类型!)

我仍然可以做E = static_cast<unsigned int>(constant),但它太冗长了(在我现实生活中的代码中,每个枚举值都是由constexpr函数调用初始化的,很难放在static_cast<unsigned int>任何地方)。

c++ enums initialization constexpr scoped-enums

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

在常量表达式中访问联合成员时出错

当我遇到问题时,我正在用工会做一些实验。

union U
{
  // struct flag for reverse-initialization of each byte
  struct rinit_t { };
  constexpr static const rinit_t rinit{};

  uint32_t dword;
  uint8_t byte[4];

  constexpr U() noexcept : dword{} { }

  constexpr U(uint32_t x) noexcept : dword{x} { }

  constexpr U(uint32_t x, const rinit_t&) noexcept : dword{}
  {
    U temp{x};
    byte[0] = temp.byte[3];
    byte[1] = temp.byte[2];
    byte[2] = temp.byte[1];
    byte[3] = temp.byte[0];
  }
};
Run Code Online (Sandbox Code Playgroud)

这是我的示例实例:

constexpr U x{0x12345678, U::rinit};
Run Code Online (Sandbox Code Playgroud)

我在 g++ 的 5.1 和 8.1 版中遇到了这个错误-std=c++14-std=c++17 …

c++ unions constexpr

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