为什么std :: invoke不处理函数重载

时间:2017-08-04 10:55:43

标签: c++

我正在尝试一些C ++ 17功能,并遇到了std :: invoke。然后我尝试了这段代码:

#include <iostream>
#include <functional>

void f(int i) { std::cout << "fa "; }
void f(float f) { std::cout << "fb "; }

int main() {
    f(0.f);
    std::invoke(f, 0.f);
}

我收到了这些错误:

main.cpp: In function 'int main()':
main.cpp:9:23: error: no matching function for call to 'invoke(<unresolved overloaded function type>, float)'
 std::invoke(f, 0.f);

In file included from main.cpp:2:0:
c:/compilers/mingw/lib/gcc/x86_64-w64-mingw32/7.1.0/include/c++/functional:77:5: note: candidate: template<class _Callable, class ... _Args> std::invoke_result_t<_Callable, _Args ...> std::invoke(_Callable&&, _Args&& ...)
 invoke(_Callable&& __fn, _Args&&... __args)
 ^~~~~~

c:/compilers/mingw/lib/gcc/x86_64-w64-mingw32/7.1.0/include/c++/functional:77:5: note:   template argument deduction/substitution failed:
main.cpp:9:23: note:   couldn't deduce template parameter '_Callable'
 std::invoke(f, 0.f);
                   ^

我不是cpp pro,这只是为了实验目的。我可能不会在这样的情况下使用它,但为什么它无法解决函数重载?

2 个答案:

答案 0 :(得分:1)

您甚至可以将示例简化为:

void f(int i) {}
void f(float f) {}

template<typename F>
void foo(F) {}

foo(f); // compilation error here

编译错误的原因很简单:编译器不知道您将使用哪个f重载。

为了避免此类错误,您应该帮助编译器使用static_cast推导出使用显式强制转换的正确类型:

foo(static_cast<void(*)(float)>(f));

std::invoke

也是如此
std::invoke(static_cast<void(*)(float)>(f), 0.f);

答案 1 :(得分:1)

Edgar's answer explains why this gives you an error, but there is a nicer way to work around it than having to use a cast, which requires you to provide the exact function signature (which might not be known).

It involves "lifting" the overload resolution into a templated operator() function:

std::invoke([](auto&&... xs) -> decltype(auto) { return f(std::forward<decltype(xs)>(xs)...); }, 0.f);

Now this looks wordy, and it is, but you can make it more palatable with a macro:

#define LIFT(F) \
    ([](auto&&... xs) -> decltype(auto) { \
        return F(::std::forward<decltype(xs)>(xs)...); \
    })

std::invoke(LIFT(f), 0.f);