本文介绍了boost :: range ::在一个自定义调用中加入许多范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 gnzlbg 的SO问题中的解决方案部分 boost::range::加入多个范围意味着它可以在一个客户端代码调用中加入许多范围到调用 boost :: join 和 boost :: make_iterator_range 。根据这个问题,回答和注释,前者可以加入2个范围,后者是需要的,以确保使用先验的非 - const 重载。任何容器后的第二个应该完美转发通过 std :: forward 。但是我的客户端代码只能成功调用它最多有3个参数。任何更多的失败编译。有什么问题,如何解决? 我复制并粘贴了OP的实现,在这里只对空格可读性进行编辑,并添加相关的标题: #include< utility> #include< boost / range / join.hpp> template< class C> auto join(C&& c) - > declype(boost :: make_iterator_range(std :: begin(c),std :: end(c))) { return boost :: make_iterator_range(std :: begin(c),std ::端(c)); } template< class C,class D,class ... Args> auto join(C& C,D& d,Args& ... args) - > decltype ( boost :: join ( boost :: join ( boost :: make_iterator_range(std :: begin(c),std :: end(c)), boost :: make_iterator_range(std :: begin(d),std :: end(d)) args>(args)...))) { return boost :: join ( boost :: join ( boost :: make_iterator_range(std :: begin(c),std :: end(c)), boost :: make_iterator_range(std :: begin(d),std :: end ))), join(std :: forward< Args>(args)...)); } 并添加了我的客户代码: #include< deque> #include< array> #include< vector> #include< iostream> int main() { std :: deque< int> deq {0,1,2,3,4}; std :: array< int,4> stl_arr {5,6,7,8}; int c_arr [3] {9,10,11}; std :: vector< int> vec {12,13}; for(auto& i:join(deq,stl_arr,c_arr)) { ++ i; std :: cout<< i<< ,; // OK,prints 1 th to 12 } // join(deq,stl_arr,c_arr,vec); // COMPILER ERROR } 解决方案两件事情。第一个是以下声明不能按预期工作: 模板< class C> auto join(C&& c) - > decltype(boost :: make_iterator_range(std :: begin(c),std :: end(c))); template< class C,class D,class ... Args> auto join(C& C,D& d,Args& ... args) - > decltype ( boost :: join ( boost :: join ( boost :: make_iterator_range(std :: begin(c),std :: end(c)), boost :: make_iterator_range(std :: begin(d),std :: end(d)) Args(args)...) // ^^^^ - (1))); 问题的关键是在现场(1)第二次重载 join 不在范围内。使用三个参数没有问题表现,因为 Args 包具有长度1,因此产生的 join(std :: forward (arg0) / code> expand使用范围内的第一个重载。 有四个参数, > join(std :: forward< Arg0>(arg0),...,std :: forward< ArgN>(argN)) expand需要第二次重载, 一种解决方法是将函数模板集合转换为一组成员函数模板,因为类范围更宽松: struct join_type { template< class C> auto operator()(C& c)const - > declype(boost :: make_iterator_range(std :: begin(c),std :: end(c))) { return boost :: make_iterator_range(std :: begin(c),std ::端(c)); } template< class C,class D,class ... Args> auto operator()(C& C,D& d,Args& ... args)const - > decltype ( boost :: join ( boost :: join ( boost :: make_iterator_range(std :: begin(c),std :: end(c)), boost :: make_iterator_range(std :: begin(d),std :: end(d))), :forward< Args>(args)...))) { return boost :: join ( boost :: join ( boost :: make_iterator_range(std :: begin(c),std :: end(c)), boost :: make_iterator_range(std :: begin(d),std :: end(d))),(* this)(std :: forward< Args>(args)...)); } }; constexpr join_type join {}; 注意,重要的是类范围,而不是我们选择使用 operator()作为我们的成员函数模板的名称。你也可以使用名为 foo 的静态成员函数模板,并在转发给它的类之外有一个正常的函数模板。 现在我们可以揭示第二个问题,因为实现是错误的,只能使用奇数个参数!即使 join(a,b)也不会工作,但是该错误可能以前被ADL隐藏了(即客户端最终会有效地调用 boost :: join(a,b)这显然有效)( The Solution section in gnzlbg's SO question boost::range::join for multiple ranges implies it can join many ranges in one client code call to a custom function variadic template that calls boost::join and boost::make_iterator_range. According to that question, answer, and comments, the prior can join 2 ranges and the latter is needed to ensure the non-const overload of the prior is used. Any containers after the 2nd one are supposedly perfect-forwarded via std::forward. But my client code can only successfully call it with a maximum of 3 arguments. Anything more fails to compile. What’s wrong and how to fix it? And is there any Boost entity now that joins many ranges?I’ve copied and pasted that OP’s implementation, editing it here only for whitespace readability and adding the relevant headers:#include <utility>#include <boost/range/join.hpp>template<class C>auto join(C&& c)-> decltype(boost::make_iterator_range(std::begin(c), std::end(c))){ return boost::make_iterator_range(std::begin(c), std::end(c));}template<class C, class D, class... Args>auto join(C&& c, D&& d, Args&&... args)-> decltype( boost::join ( boost::join ( boost::make_iterator_range(std::begin(c), std::end(c)), boost::make_iterator_range(std::begin(d), std::end(d)) ), join(std::forward<Args>(args)...) )){ return boost::join ( boost::join ( boost::make_iterator_range(std::begin(c), std::end(c)), boost::make_iterator_range(std::begin(d), std::end(d)) ), join(std::forward<Args>(args)...) );}and added my client code:#include <deque>#include <array>#include <vector>#include <iostream>int main(){ std::deque<int> deq { 0, 1, 2, 3, 4 }; std::array<int, 4> stl_arr { 5, 6, 7, 8 }; int c_arr[3] { 9, 10, 11 }; std::vector<int> vec { 12, 13 }; for (auto& i : join(deq, stl_arr, c_arr)) { ++i; std::cout << i << ", "; // OK, prints 1 thru 12 } //join(deq, stl_arr, c_arr, vec); // COMPILER ERROR} 解决方案 There are two things going on. The first is that the following declarations won’t work as intended:template<class C>auto join(C&& c)-> decltype(boost::make_iterator_range(std::begin(c), std::end(c)));template<class C, class D, class... Args>auto join(C&& c, D&& d, Args&&... args)-> decltype( boost::join ( boost::join ( boost::make_iterator_range(std::begin(c), std::end(c)), boost::make_iterator_range(std::begin(d), std::end(d)) ), join(std::forward<Args>(args)...) // ^^^^-- (1) ));The crux of the matter is that at spot (1) the second overload of join is not in scope. With three arguments no problem manifests because the Args pack has length 1, so the resulting join(std::forward<Arg0>(arg0)) expansion uses the first overload which is in scope.With four arguments or more the resulting join(std::forward<Arg0>(arg0), ..., std::forward<ArgN>(argN)) expansion needs the second overload but it is not in scope inside the late return type of the selfsame.One way to fix that is to turn the set of function templates into a set of member function templates because class scope is more lenient:struct join_type { template<class C> auto operator()(C&& c) const -> decltype(boost::make_iterator_range(std::begin(c), std::end(c))) { return boost::make_iterator_range(std::begin(c), std::end(c)); } template<class C, class D, class... Args> auto operator()(C&& c, D&& d, Args&&... args) const -> decltype ( boost::join ( boost::join ( boost::make_iterator_range(std::begin(c), std::end(c)), boost::make_iterator_range(std::begin(d), std::end(d)) ), (*this)(std::forward<Args>(args)...) ) ) { return boost::join ( boost::join ( boost::make_iterator_range(std::begin(c), std::end(c)), boost::make_iterator_range(std::begin(d), std::end(d)) ), (*this)(std::forward<Args>(args)...) ); }};constexpr join_type join {};Note that what matters is the class scope, not that we have chosen to use operator() as the name of our member function templates. You can just as well use static member function templates named foo and have a normal function template outside of the class that forwards to it.Now we can expose the second problem in that the implementation is buggy and will only work with odd numbers of arguments! Even join(a, b) won’t work, but that bug could have been hidden previously by ADL (i.e. clients would end up effectively calling boost::join(a, b) which obviously works) ().Let’s rewrite the fold:struct join_type { template<class C> auto operator()(C&& c) const -> decltype(boost::make_iterator_range(begin(c), end(c))) { return boost::make_iterator_range(begin(c), end(c)); } template<typename First, typename Second, typename... Rest> auto operator()(First&& first, Second&& second, Rest&&... rest) const -> decltype( (*this)(boost::join(boost::make_iterator_range(begin(first), end(first)), boost::make_iterator_range(begin(second), end(second))), std::forward<Rest>(rest)...) ) { return (*this)(boost::join(boost::make_iterator_range(begin(first), end(first)), boost::make_iterator_range(begin(second), end(second))), std::forward<Rest>(rest)...); }};constexpr join_type join {}; 这篇关于boost :: range ::在一个自定义调用中加入许多范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 11-01 16:57