标签: consteval

使用引用参数嵌套调用 consteval 函数

下面的程序

template<class T>
consteval auto foo(const T&) {
   return 0;
}

template<class T>
consteval auto bar(const T& t) {
   auto n = foo(t);
   return n;
}

int main() {
   static_assert(foo("abc") == 0);
   static_assert(bar("abc") == 0);
}
Run Code Online (Sandbox Code Playgroud)

在 GCC 中构建得很好,但 Clang 拒绝了它,并显示以下消息:

error: call to consteval function 'foo<char[4]>' is not a constant expression
note: in instantiation of function template specialization 'bar<char[4]>' requested here
   static_assert(bar("abc") == 0);
note: function parameter 't' with unknown value cannot be used in a constant expression
   auto …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++20 consteval

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

为什么我们不能在 consteval 函数中使用编译时“变量”作为模板参数?

我正在测试这段代码(https://godbolt.org/z/fe6hhbeqW)...

// Returns the nth type in a parameter pack of types (ommited for clarity)
//   template <std::size_t N, typename...Ts>
//   nth_type{}

template <typename... Ts>
struct Typelist{
    template <typename T>
    consteval static std::size_t pos() noexcept { 
        for(std::size_t i{}; i < sizeof...(Ts); ++i) {
            using TN = nth_type_t<i, Ts...>;
            if (std::is_same_v<T, TN>) 
                return i;
        }
        return sizeof...(Ts);
    }
};
Run Code Online (Sandbox Code Playgroud)

我很困惑它不起作用。GCC 和 clang 同意i不作为常量表达式,因此他们拒绝让我将其作为模板参数传递。然而,i在编译时是清楚的,因此,根据我有限的理解,编译器使用它来实例化模板应该没有任何问题。

这有什么理由不起作用吗?将来有用吗?我已经用两个编译器的主干版本进行了测试,结果相同。

c++ templates metaprogramming c++20 consteval

8
推荐指数
2
解决办法
660
查看次数

consteval 构造函数必须初始化所有数据成员吗?

在下一个程序中,struct B有立即consteval默认构造函数,它不会初始化i字段。然后这个构造函数被用来创建一个临时的并且它的i字段保持不变:

struct B {
    bool b = true;
    int i;
    consteval B() {}
};

static_assert( B{}.b );
Run Code Online (Sandbox Code Playgroud)

Clang 和 MSVC 对此很满意。但海湾合作委员会抱怨道:

 error: 'B{true}' is not a constant expression
    7 | static_assert( B{}.b );
      |                  ^
error: 'B()' is not a constant expression because it refers to an incompletely initialized variable
Run Code Online (Sandbox Code Playgroud)

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

这里是哪个编译器?

更新:

我向 GCC 报告了这个问题:https://gcc.gnu.org/bugzilla/show_bug.cgi? id=104512 并通过解释关闭

这暗示 MSVC 和 clang 确实都不正确。EDG 还正确实现了 static_assert,而不是直接函数上下文。

c++ constructor language-lawyer consteval

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

gcc 允许使用另一个数组引用初始化 const 数组成员是错误的吗?

在(重新)实现一个简单的 constexpr 映射时,我写了这个(godbolt):

template <class key_type, class value_type, int N>
class flat_map
{
private:
    struct pair
    {
        key_type key;
        value_type value;
    };
    const pair elements[N];

public:
    consteval flat_map(const pair (&arr)[N]) noexcept
        : elements(arr) // works on gcc?!
    {}

    [[nodiscard]] consteval value_type operator[](const key_type key) const
    {
        for (const pair &elem : elements)
            if (elem.key == key)
                return elem.value;
        throw "Key not found";
    }
};

constexpr flat_map<int, char, 3> m = {{
    { 4, 'a' }, { -1, 'b' …
Run Code Online (Sandbox Code Playgroud)

c++ arrays member-initialization c++20 consteval

7
推荐指数
2
解决办法
813
查看次数

是否允许编译器在运行时调用立即(恒定)函数?

这可能是一个愚蠢的问题,但我感到困惑。我有一种感觉,立即(consteval)函数具有在编译时被执行,我们根本无法看到它的身体在二进制。

这篇文章显然支持我的感觉:

这意味着[immediate]函数仅在编译时可见。该函数不会发出符号,您不能使用该函数的地址,并且调试器之类的工具将无法显示它们。在这种情况下,立即函数类似于宏。

Herb Sutter的出版物中也可以找到类似的强烈主张:

请注意,C ++ 20草案已经包含了第一轮与反射相关的工作,并纳入了标准:确保函数在编译时运行的 consteval函数,这些函数来自于反射工作,并且专门用于处理反射信息。

但是,有很多证据对此事实不太清楚。

来自cppreference

consteval-指定一个函数为立即函数,也就是说,对该函数的每次调用都必须产生一个编译时常量。

这并不意味着它已经在只有编译时被调用。

P1073R3提案中

现在,人们普遍同意,将来对反射的语言支持应该使用constexpr函数,但是由于“反射函数”通常必须在编译时进行评估,因此实际上它们很可能是立即函数。

似乎这意味着我的想法,但仍未明确说出。根据同一建议:

但是,有时我们想表达的是,函数在被调用时(直接或间接)应始终产生常数,而非常数结果应产生错误。

同样,这并不意味着仅在编译时就必须评估函数。

这个答案

您的代码必须产生一个编译时常数表达式。但是编译时常量表达式在您使用它的上下文中不是可观察的属性,并且在链接甚至运行时执行它都没有副作用!在没有任何阻止的情况下

最后,有一个实时演示,其中consteval在运行时明确调用了函数。但是,我希望这是由于constevalclang尚未正确支持该事实,并且该行为实际上是不正确的,就像为什么consteval函数允许未定义的行为?

更准确地说,我想听听被引用文章的以下哪些陈述是正确的:

  1. 立即函数仅在编译时可见(并且无法在运行时评估)
  2. 不会为即时功能发出符号
  3. 诸如调试器之类的工具将无法显示即时功能

c++ language-lawyer c++20 consteval

6
推荐指数
2
解决办法
186
查看次数

`inline` 和 `noexcept` 在 consteval 上下文中是多余的吗?

我正在处理一些constexpr使用函数的代码,我目前consteval尽可能将其重构为。

inline constexpr auto example() noexcept { /*...*/ }
Run Code Online (Sandbox Code Playgroud)

据我了解inline上面的关键字在constexpr函数中已经是多余的了。

据我所知,noexcept关键字对于consteval函数来说是多余的,因为据我所知,它consteval必须在编译时进行评估,因此意味着 noexcept。这是真的还是我目前不考虑的东西(比如 constexpr exceptions)?

consteval auto example() { /*...*/ }
Run Code Online (Sandbox Code Playgroud)

c++ inline noexcept c++20 consteval

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

consteval 如何影响默认参数的评估?

在下面的代码中,如果here()停止consteval(完整 RT 或constexpr),则line()f()inside的调用行main()。但有了consteval它的定义f()。这种差异从何而来?

#include <experimental/source_location>
#include <iostream>

consteval std::experimental::source_location here(
    std::experimental::source_location loc = std::experimental::source_location::current())
{
   return loc;
}

void f(const std::experimental::source_location& a = here())
{
   std::cout << a.line() << std::endl; // will either print 17, or 10
}

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

Godbolt 链接

c++ constexpr c++20 consteval

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

decltype(fun()) 用于 consteval 方法

考虑以下代码。我可以用 GCC 10.2.0 和 Clang 11.0.0 编译它(正如预期的那样):

#include <iostream>

template<int> 
struct T {
  static constexpr auto fun() noexcept { return 0; }
  using type = std::remove_cvref_t<decltype(fun())>; 
};

int main() {
    decltype(T<1>::fun()) a = 1;
    std::cout << a; 
}
Run Code Online (Sandbox Code Playgroud)

如果我替换constexprconsteval,那么 Clang 会抱怨std::remove_cvref_t<decltype(fun())>

错误:无法在立即调用之外获取 consteval 函数“fun”的地址

GCC 编译它就好了。为什么?

c++ c++20 consteval

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

忽略参数的 consteval lambda 无法编译

我有一个 lambda 忽略其int参数并始终返回一个常量。如果我标记它consteval,编译就会失败,因为。编译器抱怨使用consteval非常量参数调用 lambda。但是参数与 lambda 有什么关系呢?

来自编译器资源管理器

来源:3:16:错误:“i”的值在常量表达式中不可用 5 | 拉姆达(i);

void bar (auto lambda, int start, int end) {
    for (int i=start; i<end; ++i) {
        lambda(i);
    }
}

int main( )
{
    auto foo = [] (int) consteval { return 2;};

    bar(foo, 1, 9);

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

c++ lambda language-lawyer c++20 consteval

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

C++ 编译时调试

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

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

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

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

c++ compilation constexpr c++20 consteval

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