У меня есть коллекция методов с разными сигнатурами, для которых всем нужен одинаковый префикс и постфиксный код, поэтому я бы хотел аккуратно завернуть каждый из них.Я пытаюсь сформулировать шаблон C ++ 14 variadic для универсальной оболочки для своих функций-членов, и у меня возникают проблемы при выводе возвращаемого типа.auto
работает, но мне нужен явно тип возвращаемого значения, чтобы обеспечить допустимое возвращаемое значение, даже если я перехватываю исключение внутри оболочки при выполнении wrappee.
До сих пор мне удалось вывести тип возврата для простогофункция-обертка, использующая std::result_of
, и я получил правильное поведение для нестатических функций-членов, использующих auto.Я два дня пытался заставить подход std::result_of
работать для функций-членов, также пробовал множество вариантов decltype()
и std::declval()
, но пока безуспешно.У меня заканчиваются идеи о том, как определить тип возвращаемого значения.
Это мой рабочий пример
#include <iostream>
int foo(int a, int b) { return a + b; }
int bar(char a, char b, char c) { return a + b * c; }
template<typename Fn, typename... Args>
typename std::result_of<Fn&(Args... )>::type
wrapFunc(Fn f, Args... args) {
//Do some prefix ops
typename std::result_of<Fn&(Args... )>::type ret = f(std::forward<Args>(args)...);
//Do some suffix ops
return ret;
}
class MemberWithAuto {
private:
public:
MemberWithAuto() {};
int foo(int i, int j) { return i + j;}
template<typename Fn, typename... Args>
auto wrapper(Fn f, Args... args) {
//Do some prefix ops
auto ret = (*this.*f)(std::forward<Args>(args)...);
//Do some suffix ops
return ret;
}
};
int main() {
std::cout << "FuncWrapper for foo with 1 + 2 returns " << wrapFunc<decltype(foo)>(foo, 1, 2) << std::endl;
std::cout << "FuncWrapper for bar with 'a' + 'b' * 1 returns " << wrapFunc<decltype(bar)>(bar, 'a','b', 1) << std::endl;
MemberWithAuto meau = MemberWithAuto();
std::cout << "MemberFunction with Auto with 6 + 1 returns " << meau.wrapper(&MemberWithAuto::foo, 6, 1) << std::endl;
return 0;
}
Оба они работают хорошо, но метод-обертка, использующий auto, не получаетмне тип возврата для последующего использования.Я перепробовал множество вариантов с std::result_of
и decltype()
со следующим кодом, но я не могу заставить его правильно скомпилировать
#include <iostream>
int foo(int a, int b) { return a + b; }
int bar(char a, char b, char c) { return a + b * c; }
class MemberWithDecl {
private:
public:
MemberWithDecl() {};
int foo(int i, int j) { return i + j;}
template<typename Fn, typename... Args>
typename std::result_of<Fn&(Args... )>::type wrapper(Fn f, Args... args) {
//Do some prefix ops
typename std::result_of<Fn&(Args... )>::type ret = (*this.*f)(std::forward<Args>(args)...);
//Do some suffix ops
return ret;
}
};
int main() {
MemberWithDecl medcl = MemberWithDecl();
std::cout << "MemberFunction with declaration also works " << medcl.wrapper(&MemberWithDecl::foo, 6, 1) << std::endl;
return 0;
}
Я ожидал найти решение, где сигнатура Fn
с Args...
правильно распознается, потому что auto
также успешно выводит типы.Кажется, что мое объявление типа не находит подходящий шаблон, независимо от того, какие варианты я пробовал, я получаю
error: no matching function for call to ‘MemberWithDecl::wrapper(int (MemberWithDecl::*)(int, int), int, int)’
Если я оставлю возвращаемый тип оболочки автоматически, и просто попробую мое объявление для переменной ret
внутри, я получаю
error: no type named ‘type’ in ‘class std::result_of<int (MemberWithDecl::*&(int, int))(int, int)>’
typename std::result_of<Fn&(Args... )>::type ret = (*this.*f)(std::forward<Args>(args)...);
После прочтения стандарта, я думаю, это означает, что result_of не считает Fn&(Args... )
правильной формой, но я не знаю, как должна выглядеть правильная формакак.
Любая помощь будет высоко ценится