26

यह सवाल एकाधिक वंशानुक्रम को following solution में के रूप में this answer में प्रस्तावित प्रेरित है छद्म अस्पष्टता है, जो बढ़ावा के लिए लैम्ब्डा आगंतुकों को लागू करने के एक अच्छा तरीका है अधिक भार :: संस्करण:घोषणा का उपयोग कर

मैं क्या करना चाहते हैं कुछ निम्न की तरह:

template <typename ReturnType, typename... Lambdas> 
struct lambda_visitor : public boost::static_visitor<ReturnType>, public Lambdas... { 
    using Lambdas...::operator(); //<--- doesn't seem to work 
    lambda_visitor(Lambdas... lambdas) : boost::static_visitor<ReturnType>() , Lambdas(lambdas)... { } 
}; 

मुझे यकीन नहीं है कि पैक की गई सूचियों के लिए क्लॉज का उपयोग करके जोड़ने का सही वाक्यविन्यास क्या होगा। using संकलन शिकायत से रोकने के लिए महत्वपूर्ण है कि operator() संदिग्ध हैं, जो पूरी तरह से नहीं हैं, क्योंकि उनके पास सभी अलग-अलग हस्ताक्षर हैं।

+3

प्रस्ताव एक [P0195R2] (http://wg21.link/p0195r2) "का उपयोग कर-घोषणाओं में पैक विस्तार" है। – Orient

+1

'उपयोग' घोषणा के संदर्भ में पैरामीटर पैक विस्तार C++ 17 मानक में है। – ThomasMcLeod

उत्तर

31

ठीक है मैं एक बहुत सभ्य समाधान पता चला:

मूल रूप से मैं, एक अतिरिक्त लैम्ब्डा मामले खोल और पैक लैम्ब्डा और आराम करने के लिए using खंड लागू होते हैं, लेकिन इस मामले में की जरूरत है के बाद से मैं जाहिरा तौर पर मैं नहीं कर सकता घोषणाओं का उपयोग करने का एक variadic सूची (कम से कम मैं वाक्य रचना पता नहीं है, यदि यह संभव है), बाकी 'आराम' मामले से इनहेरिट, इस तरह से लपेटा जाता है:

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(); 
    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(); 
    lambda_visitor(Lambda1 l1) 
     : boost::static_visitor<ReturnType>(), Lambda1(l1) 
    {} 
}; 


template <typename ReturnType> 
struct lambda_visitor<ReturnType> 
    : public boost::static_visitor<ReturnType> { 

    lambda_visitor() : boost::static_visitor<ReturnType>() {} 
}; 

तो मैं यह कर सकता हूँ दो घोषणाओं का उपयोग करके अनिवार्य रूप से, अनपॅक किए गए लैम्ब्डा प्रकार से और दूसरा माता-पिता वर्ग से, जो वास्तव में है एक कम लैम्ब्डा के साथ एक ही कक्षा।

+0

आह, मैंने आपके जवाब में आपकी टिप्पणियां देखीं और अभी इस समाधान को पोस्ट करने वाले थे :) दयालुता कि सुरुचिपूर्ण समाधान इस के साथ थोड़ा बालों वाला हो जाता है :( –

+0

@RMartinho, वास्तव में, अभी भी बहुत अच्छा समाधान नहीं है, धन्यवाद – lurscher

+0

धन्यवाद आप भी! मैंने सी ++ के एक और अजीब कोने का मामला सीखा! :) –

5

यह एक पुराना प्रश्न और एक अच्छा जवाब है। IMHO को बेहतर बनाने के लिए हम एक और चीज कर सकते हैं।

सी ++ 14 में और बेहतर हमें रिटर्न प्रकार निर्दिष्ट करने की आवश्यकता नहीं है - इसे घटाया जा सकता है।

#include <boost/variant.hpp> 
#include <type_traits> 

namespace detail { 

    template<typename... Lambdas> 
    struct lambda_visitor; 

    template<typename Lambda1, typename... Lambdas> 
    struct lambda_visitor<Lambda1, Lambdas...> 
     : public lambda_visitor<Lambdas...>, 
      public Lambda1 
    { 

     using Lambda1::operator(); 
     using lambda_visitor<Lambdas...>::operator(); 

     lambda_visitor(Lambda1 l1, Lambdas... lambdas) 
      : Lambda1(l1) 
      , lambda_visitor<Lambdas...>(lambdas...) {} 
    }; 

    template<typename Lambda1> 
    struct lambda_visitor<Lambda1> 
     : 
      public Lambda1 
    { 

     using Lambda1::operator(); 

     lambda_visitor(Lambda1 l1) 
      : Lambda1(l1) {} 
    }; 
} 

template<class...Fs> 
auto compose(Fs&& ...fs) 
{ 
    using visitor_type = detail::lambda_visitor<std::decay_t<Fs>...>; 
    return visitor_type(std::forward<Fs>(fs)...); 
}; 

उपयोग के मामले:

boost::variant<int, std::string> x = "foo", y = 4; 

auto visitor = compose([](const int& i) 
         { 
          std::cout << i << std::endl; 
         }, 
         [](const std::string& s) 
         { 
          std::cout << s << std::endl; 
         }); 

boost::apply_visitor(visitor, x); 
boost::apply_visitor(visitor, y);