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

C++ 为什么std::invoke不处理函数重载,c++,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); } #包括 #包括 v

我正在试验一些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);
}
#包括
#包括

void f(int i){std::cout您甚至可以将示例简化为:

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

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

foo(f); // compilation error here
这同样适用于
std::invoke

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

Edgar的回答解释了为什么会出现错误,但是有一种更好的解决方法,比使用强制转换更好,强制转换要求您提供准确的函数签名(可能未知)

它涉及将重载解析“提升”到模板化的
操作符()
函数中:

std::invoke([](auto&&... xs) -> decltype(auto) { return f(std::forward<decltype(xs)>(xs)...); }, 0.f);
std::invoke([](自动&&…xs)->decltype(自动){returnf(std::forward(xs)…);},0.f);
现在,这看起来很冗长,确实如此,但您可以使用宏使其更令人满意:

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

std::invoke(LIFT(f), 0.f);
定义提升(F)\ ([](自动&&…xs)->decltype(自动){\ 返回F(::std::forward(xs)…)\ }) 调用(LIFT(f),0.f);
这与
invoke
无关。您使用的名称
f
没有指定您指的是哪个
f
。解决方法有点难看:
static\u cast(f)
。谢谢,奇怪,就像我在回答中回答的那样,我认为它会更灵活。这有点不方便。乍一看,我认为由于invoke使用模板来推断函数类型,它会根据给定的函数推断签名。不过,也可以使用宏进行转换:)这太棒了,谢谢输入。我刚刚写了一个带有一些问题的长注释,我想我在写它的时候理解了为什么。我的假设是:这个提升将给定的函数指针包装在一个函子周围。它是这样工作的,因为它是一个类型实例(匿名结构),而不是一个原始(函数)指针。两个
f
函数在编译时都有不同的符号,例如
f_int
f_float
。现在,当我调用(f,…)时,它不知道我指的是
f_int
还是
f_float
,即使在编辑器中符号相同(
f
).是吗?很抱歉这么努力btw@Riptide当您编写
std::invoke(f,0.f)时
编译器必须尝试找出函数指针所要指向的
f
重载,但由于
invoke
的这个参数是一个推导的模板参数,因此它无法确定,您会得到一个歧义;它不会查看
invoke
内部以查看它是如何使用的。现在使用
LIFT
宏,我们将传递一个n实际对象。“魔法”是对象可以用任何东西调用,因为它有一个模板化的
操作符()
。因为重载解析现在发生在
操作符()
内部,而不是在模板参数推导过程中,所以没有歧义。哦,这很有意义,最后一句话让我意识到了这一点(“在这个过程中”,我很高兴也很感激能从这里的每个人身上学到这么多。
std::invoke([](auto&&... xs) -> decltype(auto) { return f(std::forward<decltype(xs)>(xs)...); }, 0.f);
#define LIFT(F) \
    ([](auto&&... xs) -> decltype(auto) { \
        return F(::std::forward<decltype(xs)>(xs)...); \
    })

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