Зачем нужен этот указатель при вызове std::call_once()?

В книге "Параллельность C++ в действии" §3.3.1, когда вводится ленточная инициализация безопасной для потока класса с использованием std::call_once(), это дает следующий пример:

#include <mutex>

struct connection_info
{};

struct data_packet
{};

struct connection_handle
{
    void send_data(data_packet const&)
    {}
    data_packet receive_data()
    {
        return data_packet();
    }
};

struct remote_connection_manager
{
    connection_handle open(connection_info const&)
    {
        return connection_handle();
    }
} connection_manager;


class X
{
private:
    connection_info connection_details;
    connection_handle connection;
    std::once_flag connection_init_flag;

    void open_connection()
    {
        connection=connection_manager.open(connection_details);
    }
public:
    X(connection_info const& connection_details_):
        connection_details(connection_details_)
    {}
    void send_data(data_packet const& data)
    {
        std::call_once(connection_init_flag,&X::open_connection,this);
        connection.send_data(data);
    }
    data_packet receive_data()
    {
        std::call_once(connection_init_flag,&X::open_connection,this);
        return connection.receive_data();
    }
};

int main()
{}

Из его документа третий параметр - это параметр, передаваемый в функцию. X::open_connection(), Почему this указатель нужен здесь при звонке std::call_once() При условии X::open_connection() не имеет входного параметра?

std::call_once(connection_init_flag,&X::open_connection,this);

PS: удаление this указатель вызовет ошибку C2064:

error C2064: term does not evaluate to a function taking 0 arguments


Обновлено: эта проблема более подробно рассматривается в п. 4.2.1 книги "Параллельность C++ в действии" при внедрении аналогичных функций, т. Е. std::async:

Если первый аргумент (должен быть вторым для std::call_once ) - указатель на функцию-член, второй аргумент (должен быть третьим для std::call_once ) предоставляет объект, к которому применяется функция-член (либо напрямую, либо через указатель, либо в виде std::ref ), а остальные аргументы передаются в качестве аргументов функции-члену. В противном случае второй (должен быть третьим для std::call_once) и последующие аргументы передаются в качестве аргументов функции или вызываемому объекту, указанному в качестве первого аргумента.

2 ответа

Решение

Зачем нужен этот указатель при вызове std::call_once()?

Так как open_connection является нестатическим членом данных. Это должно быть вызвано чем-то, и что-то является тем же экземпляром, на который указывает this (технически, нестатические функции-члены имеют неявный первый параметр для this.)

Это могло быть вызвано с другим экземпляром, хотя это не имело бы смысла в этом случае:

X x;
std::call_once(connection_init_flag, &X::open_connection, &x);

juanchopanza верен, я хотел бы добавить, что то, что вы на самом деле делаете, могло бы быть более понятным, если вы замените аргументы или ваш фрагмент кода на строго эквивалентную лямбду:

std::call_once(connection_init_flag, [&]{ open_connection(); } );
// or 
std::call_once(connection_init_flag, [this]{ open_connection(); } );

Что также в точности эквивалентно:

std::call_once(connection_init_flag, [this]{ this->open_connection(); } );
Другие вопросы по тегам