ओवरलोड रिज़ॉल्यूशन केवल तब होता है जब (ए) आप किसी फ़ंक्शन / ऑपरेटर का नाम बुला रहे हैं, या (बी) इसे एक स्पष्ट हस्ताक्षर के साथ एक पॉइंटर (फ़ंक्शन या सदस्य फ़ंक्शन) में डाल रहे हैं।
न ही यहां हो रहा है।
std::function
ऐसी कोई भी वस्तु लेता है जो उसके हस्ताक्षर के अनुकूल हो। यह विशेष रूप से एक फ़ंक्शन पॉइंटर नहीं लेता है। (एक लैम्ब्डा एक std फ़ंक्शन नहीं है, और एक std फ़ंक्शन लैम्बडा नहीं है)
अब मेरे होमब्रेव फंक्शन वेरिएंट में, हस्ताक्षर के लिए R(Args...)
मैं भी R(*)(Args...)
इस कारण से एक तर्क (सटीक मिलान) स्वीकार करता हूं । लेकिन इसका मतलब है कि यह "संगत" हस्ताक्षरों के ऊपर "सटीक मिलान" हस्ताक्षर को बढ़ाता है।
मुख्य समस्या यह है कि एक अधिभार सेट C ++ ऑब्जेक्ट नहीं है। आप एक अधिभार सेट को नाम दे सकते हैं, लेकिन आप इसे "मूल" के आसपास पारित नहीं कर सकते।
अब, आप इस तरह से एक फ़ंक्शन का छद्म अधिभार सेट बना सकते हैं:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
#define OVERLOADS_OF(...) \
[](auto&&...args) \
RETURNS( __VA_ARGS__(decltype(args)(args)...) )
यह एकल C ++ ऑब्जेक्ट बनाता है जो फ़ंक्शन नाम पर अधिभार रिज़ॉल्यूशन कर सकता है।
मैक्रोज़ का विस्तार करते हुए, हमें यह मिलता है:
[](auto&&...args)
noexcept(noexcept( baz(decltype(args)(args)...) ) )
-> decltype( baz(decltype(args)(args)...) )
{ return baz(decltype(args)(args)...); }
जो लिखने में कष्टप्रद है। एक सरल, केवल थोड़ा कम उपयोगी, संस्करण यहाँ है:
[](auto&&...args)->decltype(auto)
{ return baz(decltype(args)(args)...); }
हमारे पास एक लैम्ब्डा है जो किसी भी प्रकार के तर्कों को लेता है, फिर उन्हें आगे की ओर ले जाता है baz
।
फिर:
class Bar {
std::function<void()> bazFn;
public:
Bar(std::function<void()> fun = OVERLOADS_OF(baz)) : bazFn(fun){}
};
काम करता है। हम ओवरलोड रिज़ॉल्यूशन को लैंबडा में रखते हैं fun
, जिसे हम fun
सीधे स्टोर करते हैं , बजाय एक ओवरलोड सेट को सीधे पास करने के (जो इसे हल नहीं कर सकता है)।
C ++ भाषा में एक ऑपरेशन को परिभाषित करने के लिए कम से कम एक प्रस्ताव है जो एक फ़ंक्शन नाम को ओवरलोड सेट ऑब्जेक्ट में परिवर्तित करता है। जब तक ऐसा मानक प्रस्ताव मानक में नहीं होता है, तब तक OVERLOADS_OF
मैक्रो उपयोगी है।
आप एक कदम आगे जा सकते हैं, और कास्ट-से-संगत-फ़ंक्शन-पॉइंटर का समर्थन कर सकते हैं।
struct baz_overloads {
template<class...Ts>
auto operator()(Ts&&...ts)const
RETURNS( baz(std::forward<Ts>(ts)...) );
template<class R, class...Args>
using fptr = R(*)(Args...);
//TODO: SFINAE-friendly support
template<class R, class...Ts>
operator fptr<R,Ts...>() const {
return [](Ts...ts)->R { return baz(std::forward<Ts>(ts)...); };
}
};
लेकिन उस पर आपत्ति होने लगी है।
जीवंत उदाहरण ।
#define OVERLOADS_T(...) \
struct { \
template<class...Ts> \
auto operator()(Ts&&...ts)const \
RETURNS( __VA_ARGS__(std::forward<Ts>(ts)...) ); \
\
template<class R, class...Args> \
using fptr = R(*)(Args...); \
\
template<class R, class...Ts> \
operator fptr<R,Ts...>() const { \
return [](Ts...ts)->R { return __VA_ARGS__(std::forward<Ts>(ts)...); }; \
} \
}