gcc是否在这个概念定义中错误地评估了std::declval?

7

在这个概念定义中:

#include <utility>

template<class Func, class Ret, class... Args>
concept Invokable = requires(Func f) {
    { f(std::declval<Args>()...) } -> Ret;
};

当像这样实例化时:

static_assert(Invokable<decltype([](int){}), void, int>);

gcc-9.0.1(主干)产生了转储(确切地说是标准库的实现):

$ g++ -O2 -std=c++2a -fconcepts -Wall -Wextra -Werror -c tu1.cpp
error: static assertion failed: declval() must not be used!
2204 |       static_assert(__declval_protector<_Tp>::__stop,
     |                                               ^~~~~~

演示:https://godbolt.org/z/D0ygU4

拒绝此代码是否正确?如果不是,我做错了什么?如果是,则应该在哪里报告此错误?


备注

这是被接受的

template<auto f, class... Args>
constexpr auto size_of_return_type = sizeof(f(std::declval<Args>()...));

当这样实例化时:
static_assert(sizeof(int) == size_of_return_type<[](int){ return 0; }, int>);

演示: https://godbolt.org/z/gYGk8U

C++2a最新的草案说明:

[expr.prim.req]/2 需要表达式是一个布尔类型的prvalue,其值如下所述。出现在要求体内的表达式是未评估的操作数。

1个回答

13
这段代码是否有问题被拒绝了吗? 是的,正如你引用的语句所证明的那样,概念从未被评估。这是gcc bug 68781gcc bug 82171。 请注意,在概念中没有使用declval的理由。这更加简单:
template<class Func, class Ret, class... Args>
concept InvokableR = requires(Func&& f, Args&&... args) {
    { f(std::forward<Args>(args)...) } -> Ret;
};

declval的存在是因为你需要某种类型的表达式,而你不能只写T(),因为那需要一个默认构造函数。概念作为一流语言特性给了你这种能力。但仍然需要forward


感谢您对于需要使用 std::forward 的评论。 - YSC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接