Why can std::is_invocable not handle forwarding?
You get the same error that you get from
ForwardToFoo{}();
you have that the operator()
in ForwardToFoo
is invocable without arguments. But when it call the operator in Foo()
, without arguments... you get the error.
Is there a way to work around it?
Yes: you can SFINAE enable ForwardToFoo()::operator()
only when Foo()::operator()
is callable with the arguments.
I mean... you can write ForwardToFoo()::operator()
as follows
template<class ...Args>
constexpr auto operator()( Args &&...args ) const
-> decltype( std::declval<Foo>()(std::forward<Args>(args)...) )
{ return Foo{}( std::forward<Args>( args )... ); }
-- EDIT --
Jeff Garret notes an important point that I missed.
Generally speaking, the simple use of std::invokable
doesn't cause the instantiation of the callable in first argument.
But in this particular case the return type of ForwardToFoo::operator()
is decltype(auto)
. This force the compiler to detect the returned type and this bring to the instantiation and the error.
Counterexample: if you write the operator as a void
function that call Foo{}()
, forwarding the arguments but not returning the value,
template <typename ... Args>
constexpr void operator() ( Args && ... args ) const
{ Foo{}( std::forward<Args>( args )... ); }
now the compiler know that the returned type is void
without instantiating it.
You also get a compilation error from
static_assert( std::is_invocable_v<ForwardToFoo> == false );
but this time is because ForwardToFoo{}()
result invocable without arguments.
If you write
static_assert( std::is_invocable_v<ForwardToFoo> == true );
the error disappear.
Remain true that
ForwardToFoo{}();
gives a compilation error because this instantiate the operator.