Как напрямую привязать функцию-член к функции 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
.