Вы получаете ту же ошибку, что и от
ForwardToFoo{}();
, у вас есть то, что operator()
в ForwardToFoo
вызывается без аргументов. Но когда он вызывает оператор в Foo()
без аргументов ... вы получаете ошибку.
Есть ли способ обойти это?
Да: вы можете включить SFINAE ForwardToFoo()::operator()
только тогда, когда Foo()::operator()
вызывается с аргументами.
Я имею в виду ... вы можете написать ForwardToFoo()::operator()
следующим образом
template<class ...Args>
constexpr auto operator()( Args &&...args ) const
-> decltype( std::declval<Foo>()(std::forward<Args>(args)...) )
{ return Foo{}( std::forward<Args>( args )... ); }
- - РЕДАКТИРОВАТЬ -
Джефф Гаррет отмечает важный момент, который я пропустил.
Вообще говоря, простое использование std::invokable
не вызывает создание экземпляра вызываемого в первом аргумент.
Но в данном конкретном случае тип возвращаемого значения ForwardToFoo::operator()
равен decltype(auto)
. Это вынуждает компилятор обнаруживать возвращаемый тип, и это приводит к созданию экземпляра и ошибке.
Контрпример: если вы пишете оператор как void
функцию, которая вызывает Foo{}()
, переадресация аргументов, но не возвращение значение
template <typename ... Args>
constexpr void operator() ( Args && ... args ) const
{ Foo{}( std::forward<Args>( args )... ); }
теперь компилятор знает, что возвращаемый тип void
без его создания.
Вы также получаете ошибку компиляции из
static_assert( std::is_invocable_v<ForwardToFoo> == false );
но это время объясняется тем, что ForwardToFoo{}()
результат вызывается без аргументов.
Если вы напишите
static_assert( std::is_invocable_v<ForwardToFoo> == true );
, ошибка исчезнет.
Оставьте истину, что
ForwardToFoo{}();
выдает ошибку компиляции, потому что это создает экземпляр оператора.