With c++17 we have fancy new is_invocable
and fancy new prvalues that aren't really values.
This permits you to create an object without having to first logically construct it, then elide the construction.
I have run into a problem where using std::is_invocable
to test if you can call something, and prvalue rules, seem to collide:
struct no_move {
no_move(no_move&&)=delete;
explicit no_move(int) {}
};
void f( no_move ) {}
now can we ask if f
can be invoked using a prvalue of type no_move
?
f( no_move(1) )
std::is_invocable< decltype(&f), no_move >
doesn't work because it uses std::declval<no_move>()
which is an xvalue like no_move&&
not a prvalue of type no_move
.
In c++14 this was the same, but guaranteed elision makes some functions callable with an xvalue (i.e., "T&&
") and others with prvalues of type T
.
Is there an alternative, or do we have to invent our own trait to handle this case?
(In a theoretical world where std::declval<T>
returned T
instead of T&&
, is_invocable
would, I believe, do the right thing).
std::declval
is now broken, and needs to return exactly what was passed in? – Proboscisstd::declval2
maybe. Orstd2::declval
. But yes, astd::declval<T>
that returnedT
would makestd::is_invocable
be able to answer the above question. That falls under "invent our own trait" at this point. I wonder if any existing c++14 code would break ifdeclval<T>()
returnedT
? – Tambourinestd::declval<T>
to return exactly aT
; if that were the case then you can still dodeclval<T&&>
to do what current declval does, but by adding the reference for us it makes it impossible to "construct" the value type. – DisapprovalT
can be destroyed are then added tostd::declval<T>
based tests. So there is that. – Tambourine