获取函数重载集的函数对象

huangapple go评论72阅读模式
英文:

Getting function object for overload set

问题

This code doesn't work, because &f creates a function pointer to only one of the two f() functions, so the compiler doesn't know which one:

#include <iostream>
#include <string>

void f(int i) {
    std::cout << "f(int)" << std::endl;
}

void f(std::string str) {
    std::cout << "f(std::string)" << std::endl;
}

template<typename Callback>
void call(const Callback& callback) {
    callback(1);
    callback("a");
}

int main() {
    call(&f);
}

它不起作用,因为&f创建了一个函数指针,只指向两个f()函数中的一个,所以编译器不知道应该使用哪一个函数。

It works as intended if I instead make a template lambda function like:

call([](const auto& arg) { f(arg); });

如果我改为使用模板lambda函数,它将按预期工作:

Is there a way to do this without writing an extra lambda, that needs to pass all the arguments? For example with a std::bind expression? Or is there a limitation in the language that the overload for f only gets resolved in a function call expression?

有没有办法在不编写额外lambda表达式的情况下实现这一点,而且不需要传递所有参数?例如,使用std::bind表达式?或者是语言中只有在函数调用表达式中才会解析f的重载的限制?

英文:

This code doesn't work, because &amp;f creates a function pointer to only one of the the two f() functions, so the compiler doesn't know which one:

#include &lt;iostream&gt;
#include &lt;string&gt;

void f(int i) {
    std::cout &lt;&lt; &quot;f(int)&quot; &lt;&lt; std::endl;
}

void f(std::string str) {
    std::cout &lt;&lt; &quot;f(std::string)&quot; &lt;&lt; std::endl;
}

template&lt;typename Callback&gt;
void call(const Callback&amp; callback) {
    callback(1);
    callback(&quot;a&quot;);
}

int main() {
    call(&amp;f);
}

It works as intended if I instead make a template lambda function like

call([](const auto&amp; arg) { f(arg); });

Is there a way to do this without writing an extra lambda, that needs to pass all the arguments? For example with a std::bind expression? Or is there a limitation in the language that the overload for f only gets resolved in a function call expression?

答案1

得分: 4

调用的函数也可以通过静态转换进行选择:

int main() {
    call(static_cast<void(*)(std::string)>(&f));
}

然而,一旦你决定调用哪个重载,要么是 int 版本,要么是 std::string 版本。

要同时调用 callback(1);callback("a");,你需要在函数调用时进行重载决议(或者稍后进行,但不能在之前)。最简单的方法是使用 lambda 表达式。

Lambda 表达式在概念上类似于:

struct my_callable {
    template <typename T> 
    void operator()(const T& t) {
        f(t); // <---- 重载决议在此发生
}
};

你也可以通过以下方式实现相同的效果:

struct my_callable2 {
    void f(int i) {
        std::cout << "f(int)" << std::endl;
    }
    void f(std::string str) {
        std::cout << "f(std::string)" << std::endl;
    }
};

然而,lambda 表达式很可能会被内联,因此不会真正受益于避免一个函数调用。通过自己编写函数子类也不会减少样板代码。

英文:

The function to be called can also be choosen via a static_cast:

int main() {
    call(static_cast&lt;void(*)(std::string)&gt;(&amp;f));
}

However, once you decided which overload to call it is either the int one or the std::string one.

To call both callback(1); and callback(&quot;a&quot;); you need the overload resolution at the function call (or later, but not before as above). And the easiest way to do that is to use the lambda.

The lambda is conceptually similar to

 struct my_callable {
       template &lt;typename T&gt; 
       void operator()(const T&amp; t) {
              f(t); // &lt;---- overload resolution kicks in here
       }
 };

And you could achieve the same via

 struct my_callable2 {
     void f(int i) {
        std::cout &lt;&lt; &quot;f(int)&quot; &lt;&lt; std::endl;
     }
     void f(std::string str) {
        std::cout &lt;&lt; &quot;f(std::string)&quot; &lt;&lt; std::endl;
     }
 };

However, the lambda is likely to be inlined, hence no real benefit of avoiding one function call is to be expected. And it wont get any less boilerplate by writing the functor yourself.

huangapple
  • 本文由 发表于 2023年6月27日 21:40:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76565482.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定