"成员是私有的",尽管我不从外部访问它,但在使用尾随返回类型时
"Member is private" although I don't access it from outside, when using trailing return type
如何解决以下问题?
我正在写一些函数库,它定义了与这个问题相关的以下函数:
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,完整输出见下面的视频链接(:
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... ]
当将合成转换为std::function
时,它也非常好。但这将不允许在我的comp
函数中使用多态函子,至少我看不到任何选项。
一个"修复"是对于Comp::operator()
不使用带decltype的尾随返回类型,而是将返回类型修复为bool
(专门用于此单个测试场景(。
总结了所有四个提到的测试用例:
- Test1--直接调用组合-->确定
- Test2—使用
call
调用组合-->错误 - Test3--将组合强制转换为std::函数,然后使用
call
-->OK调用 - 测试4——使用
call
调用作文。固定返回类型Comp::operator()
到bool
-->OK
我的目标是使call
成为一个"无seemless"包装器,用于调用任何类型的函数:函数、函数指针、成员函数指针、会员变量指针等,以及使用comp
的组合。我有很多重载,但我不想为Comp<Fn1,Fn2>
引入重载,因为Fn1
或Fn2
也可以是任何类型的函数,这似乎是一个"递归问题"。
Clang编译失败的测试用例很好,我看不到任何错误,所以我认为这是一个GCC错误。如果可以的话,请提交一份错误报告,并尽量减少重复(不包括(。
注意:对于call
,在标准INVOKE
中已经有类似的东西,可以说,这不是一个宏,而是一个概念。它被std::bind
、std::function
和其他东西使用,其中一个是std::reference_wrapper
。这意味着您可以执行std::ref(fun)(args...)
以实现与call
相同的效果。
尝试用Fn1的表达式代替a,Fn2的表达式代替b,以避免提及私人成员。我在VC++中尝试过,但得到了一个不同的错误:
template<class Arg> inline
auto operator()(const Arg & arg) const -> decltype(call(Fn1(), call(Fn2(), arg))) {
return call(b, call(a, arg));
}
- 如何使用 uint64_t 键类型从 std::map<int, std::string> 返回值?
- 为什么将函数的返回类型从结构节点*更改为void后,链表的元素没有显示create_ll和显示?
- 如何在 Visual C++ 中从返回类型为 map 的函数返回 null?
- Pybind11:作为返回值的外部类型
- 从类型bankAccount的返回值到函数返回类型int没有可行的转换
- 为什么在某些情况下从函数返回类型中删除 cv 限定符?
- 模板化函数以从输入参数推断返回类型 stl-container
- 从具有泛型返回类型的 crtp 基类调用派生类中的函数
- 为什么编译器不能从返回类型中推断出模板参数?
- 从参数的返回类型推断类型
- 使用模板返回值从函数中删除类型
- 从弱指针返回类型返回共享指针
- 从保存变量数据类型的数据结构中检索值,而不指定返回类型
- 为什么 C++ 从推断的返回类型中去除引用限定符,为什么生存期延长不起作用?
- 从转发函数类型推断的模板化返回类型
- 从未知dll(c++)中检索函数(名称、返回类型、参数)
- 从函数内部推断函数返回类型
- 数据类型(从 malloc 返回)是如何转换的?
- 当我使用模板时,编译器无法将函数的返回类型从 double 转换为 int
- "成员是私有的",尽管我不从外部访问它,但在使用尾随返回类型时