Как напрямую привязать функцию-член к функции std:: в Visual Studio 11?

Я могу легко связать функции-члены с std::function, обернув их с помощью лямбда-выражения с предложением заголовка.

class Class
{
    Class()
    {
        Register([=](int n){ Function(n); });
    }

    void Register(std::function<void(int)> Callback)
    {

    }

    void Function(int Number)
    {

    }
};

Но я хочу связать их напрямую, что-то вроде следующего.

// ...
Register(&Class::Function);
// ...

Я думаю, согласно стандарту С++ 11, это должно поддерживаться. Однако в Visual Studio 11 я получаю эти ошибки компилятора.

error C2440: 'newline': невозможно преобразовать из 'int' в 'Class *'

ошибка C2647: '. *': не может разыменовать 'void (__thiscall Class:: *) (int)' в 'int'

Ответ 1

Я думаю, согласно стандарту С++ 11, это должно поддерживаться

Не так, потому что нестатическая функция-член имеет неявный первый параметр типа (cv-qualified) YourType*, поэтому в этом случае он не соответствует void(int). Следовательно, требуется std::bind:

Register(std::bind(&Class::Function, PointerToSomeInstanceOfClass, _1));

Например

Class c;
using namespace std::placeholders; // for _1, _2 etc.
c.Register(std::bind(&Class::Function, &c, _1));

Изменить. Вы упомянули, что это нужно вызывать с тем же экземпляром Class. В этом случае вы можете использовать простую не-членную функцию:

void (int n) foo
{
  theClassInstance.Function(n);
}

затем

Class c;
c.Register(foo);

Ответ 2

По словам Стефана Т. Лававей - "Избегайте использования bind(),..., используйте lambdas". https://www.youtube.com/watch?v=zt7ThwVfap0&t=32m20s

В этом случае:

Class()
{
    Register([this](int n){ Function(n); });
}

Ответ 3

Вы можете использовать std::bind:

using namespace std::placeholders;  // For _1 in the bind call

// ...

Register(std::bind(&Class::Function, this, _1));

Ответ 4

С std::function и std::bind вы можете обрабатывать разные функции члена класса одинаково.

#include <iostream>
#include <functional>
#include <vector>
using namespace std;
using namespace std::placeholders;

class Foo
{
public:
    void foo(const string &msg)
    {
        cout << msg << '\n';
    }
};

class Bar
{
public:
    void bar(const string &msg, const string &suffix)
    {
        cout << msg << suffix << '\n';
    }
};

int main(int argc, char **argv)
{
    Foo foo;
    Bar bar;

    vector<function<void (const string &msg)>> collection;
    collection.push_back(bind(&Foo::foo, &foo, _1));
    collection.push_back(bind(&Bar::bar, &bar, _1, "bar"));

    for (auto f : collection) {
        f("foo");
    }

    return 0;
}

Ответ 5

Понятия не имею, что вы пытаетесь сделать там, но я полагаю, что я сделал здесь, если это то, что вы пытаетесь сделать:

#include <chrono>
#include <iostream>
#include <functional>

auto measure = [](auto function, auto&&... parameters) -> decltype(function(parameters...))
{
    const std::chrono::steady_clock::time_point startTimePoint =
    std::chrono::steady_clock::now();

    auto returnValue = function(parameters...);

    const std::chrono::steady_clock::time_point stopTimePoint =
    std::chrono::steady_clock::now();

    const std::chrono::duration<double> timeSpan = std::chrono::duration_cast<
    std::chrono::duration<double>>(stopTimePoint - startTimePoint);

    std::cout << "Computation took " << timeSpan.count()
    << " seconds." << std::endl;

    return returnValue;
};

class Test
{
public:

    int computation(double dummy)
    {
        std::cout << "Received " << dummy << ". Computing..." << std::endl;

        return 123;
    }
};

int main(int, char**)
{
    Test instance;

    auto func = std::bind(&Test::computation, &instance, std::placeholders::_1);

    int result = measure(func, 1.0);

    std::cout << "Result: " << result << std::endl;

    return 0;
}

Ответ 6

В C++ 17 вы можете использовать:

Register([=](auto && ...args){ return Function(args...); });

что приятно, особенно если список аргументов длиннее. Конечно, список аргументов функции-члена должен быть совместим с std::function.