标签: consteval

如果 consteval 需要什么?

C++23 将引入if consteval. 这将在哪里使用,它与constexpr if?

c++ constexpr consteval c++23

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

在 C++20 中,立即函数的默认参数在哪个上下文中被替换(在源位置示例中)?

在 C++20 中添加了一个新功能来获取源位置信息:https : //en.cppreference.com/w/cpp/utility/source_location

这是该页面的一个稍微修改的示例,其中使用附加立即函数loc来获取源位置:

#include <iostream>
#include <string_view>
#include <source_location>
 
consteval auto loc(std::source_location x = std::source_location::current() ) { return x; }

void log(const std::string_view message,
         const std::source_location location = loc()) {
    std::cout << "file: "
              << location.file_name() << "("
              << location.line() << ":"
              << location.column() << ") `"
              << location.function_name() << "`: "
              << message << '\n';
}
 
template <typename T> void fun(T x) { log(x); }
 
int main(int, char*[]) {
    log("Hello world!");
    fun("Hello C++20!"); …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++20 consteval

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

constexpr 函数中的 Consteval 构造函数和成员函数调用

struct A {       
    int i;
    consteval A() { i = 2; };
    consteval void f() { i = 3; }
};

constexpr bool g() {
    A a;
    a.f();
    return true;
}

int main() {
    static_assert(g());
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/hafcab7Ga

该计划被 GCC、Clang、MSVC 和 ICC 全部拒绝,取而代之的是constexpr所有g四个consteval机构都接受它。

然而,当删除 call 时a.f();,仍然带有constexpron g,只有 ICC 仍然拒绝该代码。其他三人现在也都接受了。

我不明白为什么会这样。我的理解是,如果没有constevalon g,表达式a.f()不在直接函数上下文中,这将导致成员函数调用本身被评估为单独的常量表达式,然后无法修改成员,i因为成员的生命周期在评估期间没有开始那个常数表达式。

但为什么构造函数可以在相同的上下文中对同一个对象执行相同的操作呢?a的生命周期是否被认为是在 consteval 构造函数求值期间开始的?


另请注意, 的存在static_assert不会影响这些结果。constexpr …

c++ language-lawyer c++20 consteval

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

用户定义的文字在 C++20 中是否应该始终保持保守?

如果我没记错的话,用户定义的文字的参数在编译时总是已知的。在 C++20 中,您可以使用强制函数在编译时执行,consteval从而throw生成编译时错误。

\n
#include <limits>\n\nconsteval int operator""_int(unsigned long long int v) {\n    if (std::numeric_limits<int>::max() < v) {\n        throw "out of range";\n    }\n    return static_cast<int>(v);\n}\n\nint main() {\n    return 1\'000\'000\'000\'000_int;\n}\n
Run Code Online (Sandbox Code Playgroud)\n
$ g++ -std=c++20 main.cpp\nmain.cpp: In function \xe2\x80\x98int main()\xe2\x80\x99:\nmain.cpp:11:12:   in \xe2\x80\x98constexpr\xe2\x80\x99 expansion of \xe2\x80\x98operator""_int(1000000000000)\xe2\x80\x99\nmain.cpp:5:9: error: expression \xe2\x80\x98<throw-expression>\xe2\x80\x99 is not a constant expression\n    5 |         throw "out of range";\n      |         ^~~~~~~~~~~~~~~~~~~~\n
Run Code Online (Sandbox Code Playgroud)\n

根据我的经验,编译时错误通常比运行时错误更可取。

\n

如果必须在定义中调用其他不是 的函数constexpr,那么consteval显然不是一个选项。但除了这个例子,我想不出有什么理由不使用consteval.

\n

还有其他原因不将用户定义的文字标记为 吗consteval …

c++ constant-expression user-defined-literals c++20 consteval

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

在编译时计算“const char *”字符串哈希

我有一个计算字符串文字的哈希值的函数:

inline consteval uint64_t HashLiteral(const char* key)
{
   // body not important here...
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

在另一个函数中,我需要文字字符串及其哈希值,我想在编译时计算它:

void function(const char* s)
{
   worker(s, HashLiteral(s));
}
Run Code Online (Sandbox Code Playgroud)

然而,似乎不可能进行这样的调用function("string"),并在编译时在其主体中计算哈希值。我现在想到的最好方法是使用宏,并重新定义函数:

#define MakeHashParms(s)   s,HashLiteral(s)
void function(const char* s, const uint64_t hash)
{
   worker(s, hash);
}
function(MakeHashParms("string"));
Run Code Online (Sandbox Code Playgroud)

是否可以有更直接的解决方案?

c++ constexpr consteval

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

为什么 consteval 函数内的模板接受函数参数作为其模板参数之一?

我尝试从我的代码库中提取一个最小的工作示例:

#include <concepts>

enum class unit_type
{
};

template <typename Candidate>
concept unit_c = requires()
{
    requires std::semiregular<Candidate>;
    { Candidate::type } -> std::same_as<const unit_type&>;
};

struct unit
{
    static constexpr unit_type type{};
};

template<unit_c auto unit_1, unit_c auto unit_2>
struct unit_product
{
    static constexpr unit_type type{};
};

template <unit_c Unit1, unit_c Unit2>
consteval unit_c auto operator*(Unit1 unit_1, Unit2 unit_2) noexcept
{
    return unit_product<unit_1, unit_2>{};
}

int main()
{
    constexpr unit_c auto a = unit{} * unit{};

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码编译得很好。但为什么?我认为不能将 …

c++ templates c++20 consteval

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

如何使 consteval 函数失败?

我有以下功能:

template <size_t TSize>
consteval size_t indexOf(SomeEnum someEnum,
                         const std::array<SomeEnum, TSize> &arr) {
  for (size_t i = 0; i < TSize; ++i) {
    if (arr[i] == someEnum) {
      return i;
    }
  }
  // How to fail here?
  return SOME_DEFAULT_WRONG_VALUE;
}
Run Code Online (Sandbox Code Playgroud)

该函数应该失败而不是返回默认值,但我不能抛出异常或调用assert. 我可以static_assert在每次调用函数时添加一个(使用宏它会不那么可怕),但我更喜欢在函数中工作的解决方案。在这种情况下有没有办法触发编译失败?

c++ c++20 consteval

4
推荐指数
2
解决办法
171
查看次数

为什么 consteval/constexpr 和模板元函数之间的编译时间有如此巨大的差异?

我很好奇就编译时评估而言,我可以将 gcc 推多远,所以我让它计算了Ackermann函数,特别是输入值为 4 和 1(高于此值的任何值都是不切实际的):

consteval unsigned int A(unsigned int x, unsigned int y)
{
    if(x == 0)
        return y+1;
    else if(y == 0)
        return A(x-1, 1);
    else
        return A(x-1, A(x, y-1));
}

unsigned int result = A(4, 1);
Run Code Online (Sandbox Code Playgroud)

(我认为递归深度限制在~16K,但为了安全起见,我用它编译了这个-std=c++20 -fconstexpr-depth=100000 -fconstexpr-ops-limit=12800000000

毫不奇怪,这占用了大量的堆栈空间(实际上,如果以 8mb 的默认进程堆栈大小运行,它会导致编译器崩溃)并且需要几分钟的时间来计算。但是,它最终确实到达了那里,因此显然编译器可以处理它。

在那之后,我决定尝试使用模板、元函数和偏特化模式匹配来实现 Ackermann 函数。令人惊讶的是,以下实现只需几秒钟即可评估:

template<unsigned int x, unsigned int y>
struct A {
    static constexpr unsigned int value = A<x-1, A<x, y-1>::value>::value;
};

template<unsigned int y>
struct A<0, y> {
    static …
Run Code Online (Sandbox Code Playgroud)

c++ templates ackermann c++20 consteval

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

在模板推导时,是否可以检测保守函数是否可以运行

假设我们有一个consteval函数或一个带有consteval构造函数的简单结构,它只接受一些值:

struct A
{
    consteval A(int a)
    {
        // compile error if a < 0
        if (a < 0)
            throw "error";
    }
};
Run Code Online (Sandbox Code Playgroud)

有什么方法可以检测这样的构造函数是否可以接受 int 的非类型模板参数?我尝试过以下代码但失败了。

template <int a> concept accepted_by_A = requires() {A(a);};

int main()
{
    std::cout << accepted_by_A<-1> << std::endl; // output 1 (true)
}
Run Code Online (Sandbox Code Playgroud)

c++ templates c++20 consteval

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

使用 consteval 代替 constexpr 函数有什么优点?

我知道需求的差异,我最感兴趣的是它带来的代码质量带来的好处。

我能想到的几件事:

  • 读者可以只读取函数签名并知道该函数在编译时被评估
  • 编译器可能会发出更少的代码,因为constevalfns 在运行时从不使用(这是推测性的,我没有这方面的真实数据)
  • 不需要有变量来强制ctfe,最后的例子

注意:如果代码质量太模糊,我理解有些人可能想要结束这个问题,对我来说代码质量并不是那么模糊的术语,但是......

例如,其中constexpr故障被延迟到运行时:

constexpr int div_cx(int a, int b)
{ 
  assert(b!=0);
  return a/b;
}
    
int main()
{
    static constexpr int result = div_cx(5,0); // compile time error, div by 0
    std::cout << result; 
    std::cout << div_cx(5,0) ; // runtime error :( 
}
Run Code Online (Sandbox Code Playgroud)

c++ constexpr c++20 consteval

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