为什么std :: is_invocable无法转发句柄?

问题描述 投票:4回答:3

我有一个仅将函数调用转发到另一个类的类,并且我希望能够在我的转发类上使用std::invocable<>。但是由于某些原因而失败...这是我应该期待的吗?有没有解决的办法?

#include <type_traits>
#include <utility>

struct Foo {
    constexpr int operator()( int i ) const {
        return i;
    }
};

struct ForwardToFoo {
    template<class ...Args>
    constexpr decltype(auto) operator()( Args &&...args ) const {
        Foo foo;
        return foo( std::forward<Args>( args )... );
    }
};

int main( void ) {
    // These work fine
    static_assert( std::is_invocable_v<ForwardToFoo, int> == true );
    static_assert( std::is_invocable_v<Foo, int> == true );
    static_assert( std::is_invocable_v<Foo> == false );

    // This causes a compiler error
    static_assert( std::is_invocable_v<ForwardToFoo> == false );

    return 0;
}

编辑:到目前为止的答案表明,问题在于最后一个static_assert()会强制将ForwardToFoo::operator()<>实例化为没有参数,从而触发编译器错误。那么,有没有一种方法可以将该实例化错误转换为SFINAE错误,而无需编译器错误就可以对其进行处理?

c++ c++17 perfect-forwarding
3个回答
3
投票

您遇到与您相同的错误

ForwardToFoo{}();

您具有operator()中的ForwardToFoo可以不带参数地调用。但是,当它在Foo()中调用运算符时,如果没有参数,则会出现错误。

是否有解决方法?

是:只有当可使用参数调用ForwardToFoo()::operator()时,才可以SFINAE启用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 )... ); }

1
投票

我无法完全弄清为什么您希望这样做有效。

Foo要求int是可调用的,因此ForwardToFoo也是如此。否则,其对Foo的调用将格式错误。

[您是否转发参数,复制参数或其他任何东西都没有关系:仍然需要提供它们。

考虑如何调用ForwardWithFoo。你能不用争论吗?会发生什么?


0
投票

问题与转发是否无关。在最后一个static_assert中,您要求编译器将不带参数的ForwardToFoo::operator()实例化。在该运算符中,您调用的Foo::operator()仅具有一个int的重载。显然,这会导致硬编译器错误。

std::is_invocable在其他情况下有效,因为它实际上不会实例化不存在的运算符。

您对代码的潜在解决方法是强制至少一个参数传递给ForwardToFoo::operator()

struct ForwardToFoo {
    template<class Arg0, class ...Args>
    constexpr decltype(auto) operator()( Arg0 arg0, Args ...args ) const {
        Foo foo;
        return foo(arg0, args...);

    }
};

然后,编译器将不会实例化该运算符(因为没有参数就无法调用它。)>

或者您可以使用其他答案中所示的expression-sfinae。

请参见live example

© www.soinside.com 2019 - 2024. All rights reserved.