什么是 C++ 中的可调用对象?
Posted
技术标签:
【中文标题】什么是 C++ 中的可调用对象?【英文标题】:What is a callable object in C++? 【发布时间】:2013-10-17 04:32:50 【问题描述】:我目前正在研究提升线程。我发现线程类有一个接受可调用对象的构造函数。什么是可调用对象?
class CallableClass
private:
// Number of iterations
int m_iterations;
public:
// Default constructor
CallableClass()
m_iterations=10;
// Constructor with number of iterations
CallableClass(int iterations)
m_iterations=iterations;
// Copy constructor
CallableClass(const CallableClass& source)
m_iterations=source.m_iterations;
// Destructor
~CallableClass()
// Assignment operator
CallableClass& operator = (const CallableClass& source)
m_iterations=source.m_iterations;
return *this;
// Static function called by thread
static void StaticFunction()
for (int i=0; i < 10; i++) // Hard-coded upper limit
cout<<i<<"Do something in parallel (Static function)."<<endl;
boost::this_thread::yield(); // 'yield' discussed in section 18.6
// Operator() called by the thread
void operator () ()
for (int i=0; i<m_iterations; i++)
cout<<i<<" - Do something in parallel (operator() )."<<endl;
boost::this_thread::yield(); // 'yield' discussed in section 18.6
;
这如何成为可调用对象?是因为操作符重载还是构造函数还是其他原因?
【问题讨论】:
因为operator()
,是的。见here。此外,此上下文中的“可调用对象”还包括函数、函数指针和 lambda 函数。
这是超载的operator()
。它使您可以像调用函数一样调用该类的实例。它们被称为 functors、function objects、callable objects 等。
你应该用 boost 标记(和命名)这个问题。 Boost 不是一个标准的 C++ 库,所以如果你正确地标记和命名它,这里非常大的 boost 社区可能能够更快地了解它。
【参考方案1】:
可调用对象是可以像函数一样被调用的东西,语法为object()
或object(args)
;即函数指针,或者重载operator()
的类类型的对象。
类中operator()
的重载使其可调用。
【讨论】:
【参考方案2】:这里有两个步骤。在 C++ 标准中,“函数对象”是可以出现在带括号的参数列表左侧的对象,即指向函数的指针或类型具有一个或多个 operator()
s 的对象。术语“可调用对象”更广泛:它还包括指向成员的指针(不能用正常的函数调用语法调用)。可调用对象是可以传递给std::bind
等的东西。参见 20.8.1 [func.def] 和 20.8[function.objects]/1。
【讨论】:
【参考方案3】:可调用对象是来自具有operator()
重载的类的对象实例:
struct Functor
ret_t operator()();
// ...
Functor func; // func is a callable object
或取消引用的函数指针:
ret_t func()
// ...
func; // func converts to a callable object
【讨论】:
“函数不是对象...(§1.8/1)” @MM.:这就是为什么答案说“一个函数指针”,而不是“一个函数”。也许代码注释可以更精确,例如“func 转换为可调用对象”。 @MikeSeymour:确实 函数指针 是一个对象,但它是不可调用的。事实上,取消引用函数指针是可调用的,IMO。我说的对吗? @MM。 - 函数指针是可调用的:f(3)
。不要深入了解是否必须取消引用函数指针的细节。 (*******f)(3)
,其中f
是一个函数指针,是有效的。【参考方案4】:
至少有一个重载的operator()
的对象是callable object,并且可以调用该运算符及其对象 like 函数调用:
CallableClass obj;
obj();
【讨论】:
我认为“可调用对象”的定义比这更广泛,但我找不到参考。可以肯定的是,带有operator()
is 的类是一个可调用对象——我只是不确定,反之亦然。
@JohnDibling:是的,我说的是“一个对象......是一个可调用的对象”而不是相反。
@JohnDibling - 你是对的:“可调用对象”包括指向成员的指针。可以用带括号的参数列表调用的东西是函数对象。
@JohnDibling 有效的现代 c++,第一版,五印或标准 c++ 库,第二版,第三印【参考方案5】:
从C++17开始,Callable对象实际上是由标准定义的;详情请见https://en.cppreference.com/w/cpp/named_req/Callable。
【讨论】:
链接坏了:(【参考方案6】:在 C++11 中,可调用元素可以是:
一个函数指针, 成员函数指针,(与上一个不同,查看here) 仿函数类的对象(实现了 operator() 的类), 匿名函数 (Lambda), 或包含在std::function 对象中的任何上述元素。这意味着您可以使用每个提到的可调用元素来启动 std::thread。看看下面的示例代码:
std::vector<int> v 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ;
int func()
return std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
class A
public:
int mem_func()
return std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
;
class B
public:
int operator()()
return std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
;
auto lambda = []() return std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>()); ;
void main()
A a;
B b;
std::function<int()> f1 = &func;
std::function<int()> f2 = std::bind(&A::mem_func, &a);
std::function<int()> f3 = std::bind(&B::operator(), &b);
std::function<int()> f4 = lambda;
std::thread t1 = std::thread(func);
std::thread t2 = std::thread(&A::mem_func, a);
std::thread t3 = std::thread(&B::operator(), b);
std::thread t4 = std::thread(lambda);
std::thread t5 = std::thread(f1);
std::thread t6 = std::thread(f2);
std::thread t7 = std::thread(f3);
std::thread t8 = std::thread(f4);
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
t8.join();
【讨论】:
【参考方案7】:函数对象添加成员函数指针产生所谓的可调用对象。 在c++ 98/03中,我们使用类覆盖operator()作为函数。一般情况下,我们称之为类函数。它具有存储函数状态的优点,其他函数不能。所以它是最重要的概念。还有边框,我们把这种风格的类函数和其他c风格的函数和指向c风格的函数的指针称为“函数对象”。 可调用对象只是“可调用”对象。它包括函数对象和成员函数指针。
【讨论】:
以上是关于什么是 C++ 中的可调用对象?的主要内容,如果未能解决你的问题,请参考以下文章