24

我目前正在研究提升线程。我发现线程类有一个接受可调用对象的构造函数。什么是可调用对象?

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
        }
    }

};

这如何成为可调用对象?是因为运算符重载还是构造函数或其他原因?

4

7 回答 7

25

可调用对象是可以像函数一样调用的东西,语法为object()or object(args); 即函数指针或重载的类类型的对象operator()

类中的重载operator()使其可调用。

于 2013-10-09T17:14:38.790 回答
7

这里有两个步骤。在 C++ 标准中,“函数对象”是可以出现在带括号的参数列表左侧的对象,即指向函数的指针或类型具有一个或多个operator()s 的对象。术语“可调用对象”更广泛:它还包括指向成员的指针(不能用正常的函数调用语法调用)。可调用对象是可以传递给std::bindetc 的东西。参见 20.8.1 [func.def] 和 20.8[function.objects]/1。

于 2013-10-09T17:54:03.420 回答
4

至少具有重载的对象operator()可调用对象,并且可以调用函数一样调用该运算符及其对象:

CallableClass obj;
obj();
于 2013-10-09T17:13:13.977 回答
4

可调用对象是来自具有operator()重载的类的对象实例:

struct Functor {
    ret_t operator()();
    // ...
}

Functor func;  // func is a callable object

或取消引用的函数指针:

ret_t func() {
   // ...
}

func;  // func converts to a callable object
于 2013-10-09T17:18:31.510 回答
2

在 C++11 中,可调用元素可以是:

  • 一个函数指针,
  • 一个成员函数指针,(和上一个不同,看这里
  • 一个仿函数类的对象(一个实现了它的 operator() 的类),
  • 匿名函数(Lambdas),
  • 或者包含在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();
}
于 2019-03-11T17:01:49.117 回答
2

从 C++17 开始,Callable 对象实际上是由标准定义的;有关详细信息,请参阅https://en.cppreference.com/w/cpp/named_req/Callable

于 2017-04-20T23:42:47.507 回答
1

函数对象添加成员函数指针产生所谓的可调用对象。在c++ 98/03中,我们使用类覆盖operator()作为函数。一般情况下,我们称之为类函数。它具有存储函数状态的优点,其他函数不能。所以它是最重要的概念。还有边框,我们把这种风格的类函数和其他c风格的函数和指向c风格的函数的指针称为“函数对象”。可调用对象只是“可调用”对象。它包括函数对象和成员函数指针。

于 2016-01-08T01:53:34.380 回答