<bdo id='N8dYc'></bdo><ul id='N8dYc'></ul>

<small id='N8dYc'></small><noframes id='N8dYc'>

  1. <i id='N8dYc'><tr id='N8dYc'><dt id='N8dYc'><q id='N8dYc'><span id='N8dYc'><b id='N8dYc'><form id='N8dYc'><ins id='N8dYc'></ins><ul id='N8dYc'></ul><sub id='N8dYc'></sub></form><legend id='N8dYc'></legend><bdo id='N8dYc'><pre id='N8dYc'><center id='N8dYc'></center></pre></bdo></b><th id='N8dYc'></th></span></q></dt></tr></i><div id='N8dYc'><tfoot id='N8dYc'></tfoot><dl id='N8dYc'><fieldset id='N8dYc'></fieldset></dl></div>
  2. <legend id='N8dYc'><style id='N8dYc'><dir id='N8dYc'><q id='N8dYc'></q></dir></style></legend>

    1. <tfoot id='N8dYc'></tfoot>

      使用 lambdas 进行变量访问的最佳方法

      时间:2023-07-01
        <tbody id='SRXiz'></tbody>
    2. <i id='SRXiz'><tr id='SRXiz'><dt id='SRXiz'><q id='SRXiz'><span id='SRXiz'><b id='SRXiz'><form id='SRXiz'><ins id='SRXiz'></ins><ul id='SRXiz'></ul><sub id='SRXiz'></sub></form><legend id='SRXiz'></legend><bdo id='SRXiz'><pre id='SRXiz'><center id='SRXiz'></center></pre></bdo></b><th id='SRXiz'></th></span></q></dt></tr></i><div id='SRXiz'><tfoot id='SRXiz'></tfoot><dl id='SRXiz'><fieldset id='SRXiz'></fieldset></dl></div>

      <tfoot id='SRXiz'></tfoot>

        • <small id='SRXiz'></small><noframes id='SRXiz'>

                <bdo id='SRXiz'></bdo><ul id='SRXiz'></ul>
                <legend id='SRXiz'><style id='SRXiz'><dir id='SRXiz'><q id='SRXiz'></q></dir></style></legend>

                本文介绍了使用 lambdas 进行变量访问的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                问题描述

                我想使用 lambda 内联对变体类型的访问.目前我有以下代码:

                I want to inline visitation of variant types with lambdas. At the moment i have the following code:

                struct Foo {
                    boost::variant< boost::blank , int , string , vector< int >  > var;
                
                    template <typename T, typename IL , typename SL , typename VL>
                    void ApplyOptionals( T& ref, IL&& intOption , SL&& stringOption , VL&& vectorOption ) {
                        if (var.which() == 1) {
                            intOption( ref , boost::get< int >(var) );
                        } else if (var.which() ==2) {
                            stringOption( ref , boost::get< string>(var) );
                        } else if (var.which() == 3) {
                            vectorOption( ref , boost::get< vector< int > >(var) );
                        }
                    };
                };
                // ...
                myFooV.ApplyOptionals(
                    obj,
                    [](Obj& o, int v) -> void { cout << "int: " << v << endl; o.value = v; },
                    [](Obj& o, string v) -> void{ cout << "string: " << v << endl; o.name = v; },
                    [](Obj& o, vector< int >& v) -> void{ v.push_back(257); cout << " vector.. has elements: " << v.size() << endl; o.ids = v; }
                );
                

                然而,这种方法的主要缺点是它取决于变体类型参数的顺序,并且不会在编译时检测像 boost::static_visitor 这样的未处理类型

                However the main drawback of this approach is that it depends on the order of variant type parameters and doesn't detect at compile-time unhandled types like boost::static_visitor would do

                我可以从这两种方法中获得最佳效果吗?

                Can i get the best of both approaches?

                正在研究 RMartinho 的出色答案,我正在尝试解决此错误,似乎该变体认为 operator() 调用不明确(我使用的是 g++ 4.5.1,就像它看不到一样lambda 运算符.

                Working on the excellent answer from RMartinho, i'm trying to work out this error, it seems that variant thinks the operator() calls are amibiguous (i'm using g++ 4.5.1, it's like it couldn't see the lambda operators.

                看这个问题请求成员`...'是模棱两可的g++,似乎c++不喜欢用多重继承作为提供多重重载的方式(即使由于签名不同,调用完全没有歧义)

                looking at this question request for member `...' is ambiguous in g++, it seems that c++ doesn't like multiple inheritance as a way to provide multiple overloads (even if the calls are completely non-ambiguous because of different signature)

                #include <iostream>
                #include <string>
                #include <vector>
                #include <boost/variant.hpp>
                
                using namespace std;
                
                typedef boost::variant< boost::blank , int , string , vector< int >  > var_t;
                
                template <typename ReturnType, typename... Lambdas>
                struct lambda_visitor : public boost::static_visitor<ReturnType>, public Lambdas... {
                    lambda_visitor(Lambdas... lambdas) : Lambdas(lambdas)... { }
                };
                
                template <typename ReturnType>
                struct lambda_visitor<ReturnType> : public boost::static_visitor<ReturnType> {
                    lambda_visitor() {}
                };
                
                
                template <typename ReturnType, typename... Lambdas>
                lambda_visitor<ReturnType, Lambdas...> make_lambda_visitor(Lambdas... lambdas) {
                    return { lambdas... };
                    // you can use the following instead if your compiler doesn't
                    // support list-initialization yet
                    // return lambda_visitor<ReturnType, Lambdas...>(lambdas...);
                }
                
                int main() {
                    vector< int > vit;
                    vit.push_back(7);
                
                    var_t myFooV = vit;
                
                    auto visitor = make_lambda_visitor<void>(
                        [](int v) -> void { cout << "int: " << v << endl; },
                        [](string& v) -> void{ cout << "string: " << v << endl; },
                        [](vector< int >& v) -> void{ v.push_back(27); boost::get< vector< int > >(myFooV).push_back(34);  cout << " vector.. has elements: " << v.size() << endl; }
                    );
                
                    cout << " and for the grand finale.. " << endl;
                
                    boost::apply_visitor( visitor , myFooV );
                };
                

                这给了我大致一堆模板提升错误,但不同的部分是:

                This, gives me roughly a bunch of template boost errors, but the distinct part is:

                boost_1_46_0/boost/variant/variant.hpp:832:32: error: request for member ‘operator()’ is ambiguous
                test2.cpp:44:54: error: candidates are: main()::<lambda(std::vector<int>&)>
                test2.cpp:43:47: error:                 main()::<lambda(std::string&)>
                test2.cpp:42:55: error:                 main()::<lambda(int)>
                boost_1_46_0/boost/variant/variant.hpp:832:32: error: return-statement with a value, in function returning 'void'
                

                这是整个错误,以防万一我遗漏了一些其他相关信息:

                This is the whole error, just in case i'm missing some other relevant info:

                boost_1_46_0/boost/variant/variant.hpp: In member function ‘boost::detail::variant::invoke_visitor<Visitor>::result_type boost::detail::variant::invoke_visitor<Visitor>::internal_visit(T&, int) [with T = std::vector<int>, Visitor = lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> >, boost::detail::variant::invoke_visitor<Visitor>::result_type = void]’:
                boost_1_46_0/boost/variant/detail/visitation_impl.hpp:130:9:   instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke_impl(int, Visitor&, VoidPtrCV, T*, mpl_::true_) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, T = std::vector<int>, typename Visitor::result_type = void, mpl_::true_ = mpl_::bool_<true>]’
                boost_1_46_0/boost/variant/detail/visitation_impl.hpp:173:9:   instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke(int, Visitor&, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, T = std::vector<int>, NoBackupFlag = boost::variant<boost::blank, int, std::basic_string<char>, std::vector<int> >::has_fallback_type_, typename Visitor::result_type = void]’
                boost_1_46_0/boost/variant/detail/visitation_impl.hpp:260:1:   instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor&, VoidPtrCV, mpl_::false_, NoBackupFlag, Which*, step0*) [with Which = mpl_::int_<0>, step0 = boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<4l>, boost::blank, boost::mpl::l_item<mpl_::long_<3l>, int, boost::mpl::l_item<mpl_::long_<2l>, std::basic_string<char>, boost::mpl::l_item<mpl_::long_<1l>, std::vector<int>, boost::mpl::l_end> > > > >, boost::mpl::l_iter<boost::mpl::l_end> >, Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, NoBackupFlag = boost::variant<boost::blank, int, std::basic_string<char>, std::vector<int> >::has_fallback_type_, typename Visitor::result_type = void, mpl_::false_ = mpl_::bool_<false>]’
                boost_1_46_0/boost/variant/variant.hpp:1776:13:   instantiated from ‘static typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, T0_ = boost::blank, T1 = int, T2 = std::basic_string<char>, T3 = std::vector<int>, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
                boost_1_46_0/boost/variant/variant.hpp:1787:13:   instantiated from ‘typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor(Visitor&) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, T0_ = boost::blank, T1 = int, T2 = std::basic_string<char>, T3 = std::vector<int>, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
                boost_1_46_0/boost/variant/variant.hpp:1810:52:   instantiated from ‘typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::apply_visitor(Visitor&) [with Visitor = lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> >, T0_ = boost::blank, T1 = int, T2 = std::basic_string<char>, T3 = std::vector<int>, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
                boost_1_46_0/boost/variant/detail/apply_visitor_unary.hpp:60:43:   instantiated from ‘typename Visitor::result_type boost::apply_visitor(Visitor&, Visitable&) [with Visitor = lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> >, Visitable = boost::variant<boost::blank, int, std::basic_string<char>, std::vector<int> >, typename Visitor::result_type = void]’
                test2.cpp:49:40:   instantiated from here
                boost_1_46_0/boost/variant/variant.hpp:832:32: error: request for member ‘operator()’ is ambiguous
                test2.cpp:44:54: error: candidates are: main()::<lambda(std::vector<int>&)>
                test2.cpp:43:47: error:                 main()::<lambda(std::string&)>
                test2.cpp:42:55: error:                 main()::<lambda(int)>
                boost_1_46_0/boost/variant/variant.hpp:832:32: error: return-statement with a value, in function returning 'void'
                

                结论:

                我想添加此实用程序的最终版本,包括测试:

                conclusion:

                I want to add the final version of this utility, including tests:

                #include <boost/variant.hpp>
                
                namespace Variant {
                    template <typename ReturnType, typename... Lambdas>
                    struct lambda_visitor;
                
                    template <typename ReturnType, typename Lambda1, typename... Lambdas>
                    struct lambda_visitor< ReturnType, Lambda1, Lambdas...>
                    : public lambda_visitor<ReturnType, Lambdas...>, public Lambda1 {
                        using Lambda1::operator();
                        using lambda_visitor< ReturnType, Lambdas...>::operator();
                        typedef ReturnType ReturnType_t;
                
                        lambda_visitor(Lambda1 l1, Lambdas... lambdas) : Lambda1(l1), lambda_visitor< ReturnType, Lambdas...> (lambdas...) {
                        }
                
                        lambda_visitor(Lambda1 && l1, Lambdas && ... lambdas) : Lambda1(l1), lambda_visitor< ReturnType, Lambdas...> (lambdas...) {
                        }
                    };
                
                    template <typename ReturnType, typename Lambda1>
                    struct lambda_visitor<ReturnType, Lambda1>
                    : public boost::static_visitor<ReturnType>, public Lambda1 {
                        using Lambda1::operator();
                        typedef ReturnType ReturnType_t;
                
                        lambda_visitor(Lambda1 l1) : boost::static_visitor<ReturnType > (), Lambda1(l1) {
                        }
                
                        lambda_visitor(Lambda1 && l1) : boost::static_visitor<ReturnType > (), Lambda1(l1) {
                        }
                    };
                
                    template <typename ReturnType>
                    struct lambda_visitor<ReturnType> : public boost::static_visitor<ReturnType> {
                
                        typedef ReturnType ReturnType_t;
                        lambda_visitor() : boost::static_visitor<ReturnType > () {
                        }
                    };
                
                    template <typename ReturnType>
                    struct default_blank_visitor {
                
                        typedef ReturnType ReturnType_t;
                        inline ReturnType operator() (const boost::blank&) const {
                            return (ReturnType) 0;
                        };
                    };
                
                    template<>
                    struct default_blank_visitor<void> {
                
                        typedef void ReturnType_t;
                        inline void operator() (const boost::blank&) const {};
                    };
                
                    template <typename ReturnType, typename... Lambdas>
                    lambda_visitor<ReturnType, default_blank_visitor< ReturnType >, Lambdas...> make_lambda_visitor(Lambdas... lambdas) {
                        return
                        {
                            default_blank_visitor<ReturnType > (), lambdas...
                        };
                        // you can use the following instead if your compiler doesn't
                        // support list-initialization yet
                        //return lambda_visitor<ReturnType, default_blank_visitor<ReturnType> , Lambdas...>( default_blank_visitor<ReturnType>(), lambdas...);
                    };
                    /*
                    template <typename ReturnType, typename... Lambdas>
                    lambda_visitor<ReturnType, default_blank_visitor< ReturnType >, Lambdas...> make_lambda_visitor(Lambdas && ... lambdas) {
                        return
                        {
                            default_blank_visitor<ReturnType > (), lambdas...
                        };
                        // you can use the following instead if your compiler doesn't
                        // support list-initialization yet
                        //return lambda_visitor<ReturnType, default_blank_visitor<ReturnType> , Lambdas...>( default_blank_visitor<ReturnType>(), lambdas...);
                    };*/
                
                    template <typename ReturnType, typename... Lambdas>
                    lambda_visitor<ReturnType, Lambdas...> make_lambda_visitor_override_blank(Lambdas... lambdas) {
                        return
                        {
                            lambdas...
                        };
                        // you can use the following instead if your compiler doesn't
                        // support list-initialization yet
                        //return lambda_visitor<ReturnType, Lambdas...>(lambdas...);
                    }
                
                
                    namespace basic_usage 
                    {
                        struct Test
                        {
                            typedef boost::variant< boost::blank , int , double > variant_t;
                            void run()
                            {
                                variant_t a, b, c;
                                a = 42;
                                b = 3.14159265;
                                auto visitor = Variant::make_lambda_visitor<int>( [](int v) -> int { return v+1; } , [](double v) -> int { return (int)v*2; } );
                                int result = boost::apply_visitor(visitor, a);
                                HAssertMsg( result == (42 + 1) , "unexpected");
                                result = boost::apply_visitor( visitor , b);
                                HAssertMsg( result == 6 , "unexpected");
                                auto blankVisitor = Variant::make_lambda_visitor_override_blank<int>( 
                                [](int v) -> int { return -1; } 
                                , [](double v) -> int { return -1; }
                                , [](boost::blank ) -> int { return 0;} );
                                result = boost::apply_visitor( blankVisitor , c);
                                HAssertMsg( result == 0 , "unexpected");
                
                                //same as previous case, but using lambda coalescing :-)
                                auto blankVisitor2 = Variant::make_lambda_visitor_override_blank<int>( 
                                [](boost::variant< int , double >& v) -> int { return -1; } 
                                , [](boost::blank ) -> int { return 0;} );
                                result = boost::apply_visitor( blankVisitor2 , c);
                                HAssertMsg( result == 0 , "unexpected");
                                result = boost::apply_visitor( blankVisitor2 , a);
                                HAssertMsg( result == -1 , "unexpected");
                                result = boost::apply_visitor( blankVisitor2 , b);
                                HAssertMsg( result == -1 , "unexpected");
                            }
                        };
                    }
                };
                

                推荐答案

                您可以使用可变参数模板来获取 lambda,并使用继承构建一个变体访问者.这将保留编译时检查.

                You could use variadic templates to take the lambdas, and build a variant visitor using inheritance. That would retain the compile time checks.

                template <typename ReturnType, typename... Lambdas>
                struct lambda_visitor : public static_visitor<ReturnType>, public Lambdas... {
                    lambda_visitor(Lambdas... lambdas) : Lambdas(lambdas)... {}
                };
                

                还有一个小辅助函数来使用参数类型推导(lambdas 需要):

                And a little helper function to use argument type deduction (required for lambdas):

                template <typename ReturnType, typename... Lambdas>
                lambda_visitor<ReturnType, Lambdas...> make_lambda_visitor(Lambdas... lambdas) {
                    return { lambdas... };
                    // you can use the following instead if your compiler doesn't
                    // support list-initialization yet
                    // return lambda_visitor<ReturnType, Lambdas...>(lambdas...);
                }
                

                现在您可以让访问者像这样:

                Now you can make visitors like this:

                auto visitor = make_lambda_visitor<int>([](int) { return 42; },
                                                        [](std::string) { return 17; },
                                                        [](std::vector<int>) { return 23; });
                

                注意:由于我不知道重载解析过程的细节,这个优雅的解决方案会导致奇怪的歧义错误:(

                Note: due to a detail of the overload resolution process that I wasn't aware of, this elegant solution causes weird ambiguity errors :(

                请参阅后续问题以了解修复方法.

                See the follow-up question for the fix.

                这篇关于使用 lambdas 进行变量访问的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                上一篇:如何在 C++11 中将 lambda 表达式存储为类的字段? 下一篇:lambdas 需要捕获“this"来调用静态成员函数?

                相关文章

                  <bdo id='yVwKN'></bdo><ul id='yVwKN'></ul>

              • <i id='yVwKN'><tr id='yVwKN'><dt id='yVwKN'><q id='yVwKN'><span id='yVwKN'><b id='yVwKN'><form id='yVwKN'><ins id='yVwKN'></ins><ul id='yVwKN'></ul><sub id='yVwKN'></sub></form><legend id='yVwKN'></legend><bdo id='yVwKN'><pre id='yVwKN'><center id='yVwKN'></center></pre></bdo></b><th id='yVwKN'></th></span></q></dt></tr></i><div id='yVwKN'><tfoot id='yVwKN'></tfoot><dl id='yVwKN'><fieldset id='yVwKN'></fieldset></dl></div>
              • <small id='yVwKN'></small><noframes id='yVwKN'>

                1. <tfoot id='yVwKN'></tfoot>

                    <legend id='yVwKN'><style id='yVwKN'><dir id='yVwKN'><q id='yVwKN'></q></dir></style></legend>