C++ 为什么std::invoke不处理函数重载
我正在试验一些C++17特性,遇到了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
#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);