У меня есть класс CallProtector
, который должен вызывать метод с переменным количеством аргументов, которые предполагают защиту вызова через мьютекс, но я не могу понять, как передать метод объекта с их аргументами. Вот что у меня есть до сих пор:
class CallProtector
{
public:
template<typename F, typename ...Args>
void callProtectedMethod(F& lambda, Args... args)
{
std::lock_guard<std::mutex> guard(m_guard);
lambda(args);
}
private:
std::mutex m_guard;
};
Я пытаюсь использовать это следующим образом:
class Car
{
public:
void updateEngine(int engineModelType) {}
};
int main()
{
Car alfaRomeo;
CallProtector callProtector;
callProtector.callProtectedMethod(&Car::updateEngine, 10);
return 0;
}
Но у меня ошибка компиляции, говорящая
no instance of function template "CallProtector::callProtectedMethod" matches the argument list
Ценю любую помощь, заранее спасибо.
Начиная с C++17, вы можете использовать std::invoke
, просто перенаправляя ему все аргументы:
template<typename ...Args>
void callProtectedMethod(Args&&... args)
{
std::lock_guard<std::mutex> guard(m_guard);
std::invoke(std::forward<Args>(args)...);
}
также, если вы хотите вызвать функцию-член в экземпляре автомобиля, вам нужно передать указатель на объект.
@Oleg Почему бы не сделать callProtectedMethod
функцией, принимающей любой вызываемый объект? Демо, переданный callable может быть создан как замыкание или результат std::bind
функции - нет проблем с передачей аргументов, просто вызываем функцию с защитой мьютекса.
Я должен использовать разные объекты и передавать на них указатель.
Следующее может сработать для вас:
class CallProtector
{
public:
template<typename F, typename ...Args>
void callProtectedMethod(F&& func, Args&&... args)
{
std::lock_guard<std::mutex> guard(m_guard);
func(std::forward<Args>(args)...);
}
private:
std::mutex m_guard;
};
а затем используйте его как:
Car alfaRomeo;
CallProtector callProtector;
auto updateEngine = std::bind(&Car::updateEngine, &alfaRomeo, std::placeholders::_1);
callProtector.callProtectedMethod(updateEngine, 10);
РЕДАКТИРОВАТЬ
Или это тоже сработает:
template<typename F, typename ...Args>
void callProtectedMethod(F&& func, Args&&... args)
{
std::lock_guard<std::mutex> guard(m_guard);
std::invoke(std::forward<F>(func), std::forward<Args>(args)...);
}
а потом
callProtector.callProtectedMethod(&Car::updateEngine, alfaRomeo, 10);
У меня это не работает, говорит: «термин не оценивает функцию, принимающую 1 аргумент». Но мы не могли просто перенаправить все аргументы в std::invoke? Это какая-то причина для этого? Это должно быть очень просто, но я действительно не могу понять.
что term
? я думаю, вы не показываете нам весь код. Это работает здесь это msvc
Спасибо, да, моя ошибка, этот код работает. Но можем ли мы избежать связывания и пересылки всех аргументов?
Я использовал этот код, чтобы заставить его работать: std::invoke(std::forward<F>(func), std::forward<Args>(args)...);
Спасибо, но это не работает для меня. Ошибка компиляции говорит, что: «вызвать» не найдена подходящая перегруженная функция. Я использую Visual Studio 2019 с С++ 17. Можем ли мы сделать то же самое с С++ 14?