In this concept definition:
#include <utility>
template<class Func, class Ret, class... Args>
concept Invokable = requires(Func f) {
{ f(std::declval<Args>()...) } -> Ret;
};
when instantiated like this:
static_assert(Invokable<decltype([](int){}), void, int>);
gcc-9.0.1 (trunk) dumps (well, the Standard Library implementation to be precise):
$ 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, | ^~~~~~
demo: https://godbolt.org/z/D0ygU4
Is it wrong to reject this code? If not, what did I do wrong? If yes, where should one report this bug?
template<auto f, class... Args>
constexpr auto size_of_return_type = sizeof(f(std::declval<Args>()...));
when instantiated like so:
static_assert(sizeof(int) == size_of_return_type<[](int){ return 0; }, int>);
Demo: https://godbolt.org/z/gYGk8U
[expr.prim.req]/2
A requires-expression is a prvalue of type bool whose value is described below. Expressions appearing within a requirement-body are unevaluated operands.
Is it wrong to reject this code?
Yes, concepts are never evaluated, as evidenced in the quote you're citing. This is gcc bug 68781 and gcc bug 82171.
Note that there's no reason to use declval
within concepts. This is more straightforward:
template<class Func, class Ret, class... Args>
concept InvokableR = requires(Func&& f, Args&&... args) {
{ f(std::forward<Args>(args)...) } -> Ret;
};
declval
exists because you need some expression of some type and you can't just write T()
because that requires a default constructor. Concepts give you that ability as a first-class language feature. Still need the forward
though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With