【发布时间】:2019-01-30 18:24:16
【问题描述】:
我有一组具有不同签名的方法,它们都需要相同的前缀和后缀代码,所以我想把它们都整齐地包装起来。
我正在尝试为我的成员函数的通用包装器制定一个 C++14 可变参数模板,但在推导返回类型时遇到了麻烦。 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)’
如果我将包装器的返回类型保留为 auto 并尝试在其中声明变量 ret,我会得到 p>
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... ) 是格式良好的,但我不知道正确的格式应该是什么样子。
任何帮助将不胜感激
【问题讨论】:
-
如果你使用
auto作为函数返回类型,没有尾随返回类型,你使用的是C++14,而不是C++11
标签: c++ c++14 wrapper variadic-templates template-argument-deduction