如何解决以下问题?
我正在编写一些函数库,它定义了与这个问题相关的以下函数:
call(f,arg)
: 调用带参数的函数。只是我在某些情况下需要的包装器。comp(f1,f2)
:返回两个函数的组合。返回一个辅助函子,表示两个函数的组合。
实现如下所示(仍然显示问题的简化版本):
// Call f with one argument
template <class Fn, class Arg>
auto call(const Fn &f, const Arg & arg) -> decltype(f(arg)) {
return f(arg);
}
// Helper functor for the function below
template<class Fn1, class Fn2>
class CompFn {
Fn1 a;
Fn2 b;
public:
CompFn(const Fn1 &f1, const Fn2 &f2) : a(f1), b(f2) {}
template<class Arg> inline
auto operator()(const Arg & arg) const -> decltype(call(b, call(a, arg))) {
return call(b, call(a, arg));
}
};
/** Composition of f1 and f2 (f2 after f1). */
template<class Fn1, class Fn2>
CompFn<Fn1,Fn2> comp(const Fn1 &f1, const Fn2 &f2) {
return CompFn<Fn1,Fn2>(f1, f2);
}
下面的代码用作一个简单的测试:
// Example: Take the length of the string and compare it against zero.
std::function<int(std::string)> stringLength = [](std::string s) { return s.size(); };
std::function<bool(int)> greaterZero = [](int x) { return x > 0; };
auto stringNotEmpty = comp(stringLength, greaterZero);
std::string testInput1 = "foo";
std::string testInput2 = "";
直到这里,一切正常。调用comp
本身似乎不是问题。直接调用结果函数也是可以的。但是通过调用组合会call
引入无数的编译错误(yaaay,新记录!):
assert(call(stringNotEmpty,testInput1) == true); // line 44
assert(call(stringNotEmpty,testInput2) == false);
编译输出(gcc 4.7,完整输出见下面的ideone链接):
prog.cpp:16:9: error: ‘std::function<bool(int)> CompFn<std::function<int(std::basic_string<char>)>, std::function<bool(int)> >::b’ is private
prog.cpp:44:5: error: within this context
prog.cpp:15:9: error: ‘std::function<int(std::basic_string<char>)> CompFn<std::function<int(std::basic_string<char>)>, std::function<bool(int)> >::a’ is private
prog.cpp:44:5: error: within this context
prog.cpp:22:10: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) substituting ‘template<class Fn, class Arg> decltype (f(arg)) call(const Fn&, const Arg&) [with Fn = std::function<int(std::basic_string<char>)>; Arg = std::basic_string<char>]’
prog.cpp:22:10: required by substitution of ‘template<class Arg> decltype (call(((const CompFn*)this)->CompFn<Fn1, Fn2>::b, call(((const CompFn*)this)->CompFn<Fn1, Fn2>::a, arg))) CompFn::operator()(const Arg&) const [with Arg = Arg; Fn1 = std::function<int(std::basic_string<char>)>; Fn2 = std::function<bool(int)>] [with Arg = std::basic_string<char>]’
prog.cpp:8:6: required by substitution of ‘template<class Fn, class Arg> decltype (f(arg)) call(const Fn&, const Arg&) [with Fn = std::function<int(std::basic_string<char>)>; Arg = std::basic_string<char>]’
prog.cpp:22:10: required by substitution of ‘template<class Arg> decltype (call(((const CompFn*)this)->CompFn<Fn1, Fn2>::b, call(((const CompFn*)this)->CompFn<Fn1, Fn2>::a, arg))) CompFn::operator()(const Arg&) const [with Arg = Arg; Fn1 = std::function<int(std::basic_string<char>)>; Fn2 = std::function<bool(int)>] [with Arg = std::basic_string<char>]’
prog.cpp:8:6: required by substitution of ‘template<class Fn, class Arg> decltype (f(arg)) call(const Fn&, const Arg&) [with Fn = std::function<int(std::basic_string<char>)>; Arg = std::basic_string<char>]’
prog.cpp:22:10: required by substitution of ‘template<class Arg> decltype (call(((const CompFn*)this)->CompFn<Fn1, Fn2>::b, call(((const CompFn*)this)->CompFn<Fn1, Fn2>::a, arg))) CompFn::operator()(const Arg&) const [with Arg = Arg; Fn1 = std::function<int(std::basic_string<char>)>; Fn2 = std::function<bool(int)>] [with Arg = std::basic_string<char>]’
prog.cpp:8:6: [ skipping 890 instantiation contexts ]
[ ...continues endlessly... ]
将组合转换为 astd::function
时,它也非常好。但这不允许在我的函数中使用多态函子comp
,至少我没有看到一个选项。
一个“修复”是不使用带有 decltype的尾随返回类型Comp::operator()
,而是将返回类型固定为bool
(专门针对这个单一的测试场景)。
所有四个提到的测试用例总结:
- Test1 -- 直接调用组合 --> OK
- Test2 -- 调用组合使用
call
--> 错误 - Test3 -- 将组合转换为 std::function,然后使用
call
--> OK调用 - Test4 - 使用 调用组合
call
。固定返回类型Comp::operator()
tobool
--> OK
我的目标是制作call
一个“看似简单”的包装器来调用任何类型的函数:函子、函数指针、成员函数指针、成员变量指针等......,以及使用comp
. 我有一堆重载,但我不想引入重载,Comp<Fn1,Fn2>
因为Fn1
或者Fn2
可以再次成为任何类型的函数,这似乎是一个“递归问题”。