【问题标题】:How to overload on std::function signature in C++如何在 C++ 中重载 std::function 签名
【发布时间】:2012-12-11 11:38:14
【问题描述】:

我知道以前有人问过这个问题,但尽管我是一个相当有经验的编码员,但我不明白答案,也没有办法回答这些以前的问题以要求澄清。没有“回复”链接或任何东西。此外,这些问题已经很老了。所以,我重新提出这个问题。

我有一个类,我在其中重载了 += 运算符。我希望一个重载采用裸函数指针,另一个采用 std::function:

void operator+=(void (*handler)());
void operator+=(function<void (void *, T)> handler);

用法:

MyClass a;
a += [](){ DoSomething(); };
a += [](void *x, T y){ DoSomething(); };

很遗憾,代码无法编译,因为编译器无法确定第二个重载不适合第一个 += 调用。

如何定义我的 operator+= 成员函数来纠正这个问题?我不想更改运算符的使用方式(例如,通过使用显式强制转换)。我希望它们能像上面演示的那样工作。

此外,还有以下重载也很方便:

void operator+=(function<void()> handler);

但同样,我不能根据函数模板的签名重载。

有关更多示例,请参阅此线程:Isn't the template argument (the signature) of std::function part of its type? (我尝试实现该线程中提到的各种解决方案,它们都无法编译

多年来我一直在使用多种语言进行编程,但我的 C++ 技能有点生疏。

【问题讨论】:

  • 的问题是:你打算在你的重载operator+= 中使用给定的函数指针或std::function 对象做什么?
  • @zaufi:我看不出这有什么关系,但没关系。我将把它添加到事件处理函数的 std::vector 中。我本质上是在 C++ 中实现 .NET 事件。因为事件和属性(如闭包)对于现代编程语言来说绝对是必不可少的功能。
  • 那么,你必须有一个std::vectorstd::function 实例化,并带有一个(我建议void())签名......我说的对吗?
  • @zaufi:我不确定我是否跟随。每当我调用 += 运算符时,我都希望将传递的函数(或原始函数指针)添加到函数向量中。问题是让编译器选择正确的重载。

标签: c++ lambda overloading signature


【解决方案1】:

以下代码适用于 g++ 4.7.2:

#include <functional>
#include <iostream>

template <typename T>
typename std::enable_if<std::is_convertible<T, void(*)()>::value>::type
foo(T&&)
{
    std::cout << "foo(void(*)())" << std::endl;
}

void foo(std::function<void(void*,int)>)
{
    std::cout << "foo(std::function<void(void*,int)>)" << std::endl;
}

int main()
{
    foo([]{});
    foo([](void*,int){});
}

问题是由std::function的构造函数引起的,它被声明为template &lt;class F&gt; function(F);。该构造函数接受所有内容作为其参数。如果该参数没有适当的operator(),则在构造函数的实例化过程中会产生错误。

不幸的是,重载解析过程不需要实例化任何模板函数,因此编译器认为一切都可以转换为任何std::function 类型。

【讨论】:

  • 谢谢,我已经成功地把它带进了我的课堂;尽管当我尝试将 T 强制转换为函数时事情有点麻烦。似乎我必须先将其转换为 void(*)() 。干杯。
  • 我认为我遇到的主要问题是我从未听说过 enable_if 并且不理解它。我模糊地意识到它可能会有所帮助(通过查看类似问题的答案),但不知道它是如何使用的。我仍然不确定它是如何工作的。
  • 关于enable_if的一些信息可以在herehere找到。
  • 谢谢,我去看看。哦,还有一个问题 - 我仍然想要有状态无参数 lambda 的重载“void operator+=(function handler)”。这也能以某种方式完成吗?
  • @WorldSEnder:它已在 C++14 中修复。添加了一个注释以限制其参与重载解析,并且它已在 gcc 4.9 中得到支持。
【解决方案2】:

好的,如果你有一个std::vector&lt;std::function&lt;void()&gt;&gt;,你甚至不需要有一堆重载。最简单的方法是定义一个模板化的operator+=,可能用std::enable_if“保护”,只为可调用的对象或函数指针打开。因此,传递 lambda 或原始指针将在分配时为您自动转换(push_back/emplace_back)。传递 std::function 将按预期分配。

【讨论】:

  • 你没有抓住重点。我想将 "[](){}" lambdas 和 "[](void *, T){}" lambdas 添加到我的向量中。我将它们包装在一个公共容器类中并将其添加到我的向量中。试图说服我不需要不同的 lambda 签名是徒劳的浪费你和我的时间。
猜你喜欢
  • 2011-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-15
  • 2011-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多