जवाब में से अधिकांश मूल रूप से सवाल का जवाब देने पर ध्यान केंद्रित कर रहे हैं: यह कर सकते हैं आप कॉल इन प्रकार के मूल्यों के साथ दिए गए समारोह वस्तु । यह हस्ताक्षर से मेल खाने जैसा नहीं है, क्योंकि यह कई अंतर्निहित रूपांतरणों की अनुमति देता है जो आप कहते हैं कि आप नहीं चाहते हैं। अधिक सख्त मैच पाने के लिए हमें टीएमपी का एक गुच्छा करना है। सबसे पहले, यह उत्तर: Call function with part of variadic arguments दिखाता है कि तर्क के सटीक प्रकार और कॉल करने योग्य प्रकार के प्रकार कैसे प्राप्त करें। कोड यहाँ reproduced:
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
using result_type = ReturnType;
using arg_tuple = std::tuple<Args...>;
static constexpr auto arity = sizeof...(Args);
};
template <typename R, typename ... Args>
struct function_traits<R(&)(Args...)>
{
using result_type = R;
using arg_tuple = std::tuple<Args...>;
static constexpr auto arity = sizeof...(Args);
};
कि अब आप अपने कोड में पाता है स्थिर की एक श्रृंखला डाल सकता है किया है,:
struct A {
using Signature = void(int, double);
template <typename Callable>
void Register(Callable &&callable) {
using ft = function_traits<Callable>;
static_assert(std::is_same<int,
std::decay_t<std::tuple_element_t<0, typename ft::arg_tuple>>>::value, "");
static_assert(std::is_same<double,
std::decay_t<std::tuple_element_t<1, typename ft::arg_tuple>>>::value, "");
static_assert(std::is_same<void,
std::decay_t<typename ft::result_type>>::value, "");
callback = callable;
}
std::function<Signature> callback;
};
जब से तुम मूल्य से गुजर रहे हैं यह सब आप की जरूरत मूल रूप से है। यदि आप संदर्भ से गुजर रहे हैं, तो मैं एक अतिरिक्त स्थिर जोर जोड़ूंगा जहां आप अन्य उत्तरों में से एक का उपयोग करते हैं; शायद songyuanyao का जवाब। यह उन मामलों का ख्याल रखेगा जहां उदाहरण के लिए आधार प्रकार समान था, लेकिन कॉन्स योग्यता गलत दिशा में गई थी।
आप जो कुछ भी करते हैं (बस स्थैतिक जोर में प्रकारों को दोहराते हुए) के बजाय आप Signature
प्रकार के सभी सामान्य बना सकते हैं। यह अच्छा होगा लेकिन इससे पहले से ही गैर-मामूली उत्तर में और भी जटिल टीएमपी जोड़ा होगा; यदि आपको लगता है कि आप इसका उपयोग कई अलग-अलग Signature
एस के साथ करेंगे या यह अक्सर बदल रहा है तो शायद उस कोड को जोड़ने के लायक भी है।
यहां एक लाइव उदाहरण है: http://coliru.stacked-crooked.com/a/cee084dce9e8dc09। विशेष रूप से, मेरा उदाहरण:
void foo(int, double) {}
void foo2(double, double) {}
int main()
{
A a;
// compiles
a.Register([] (int, double) {});
// doesn't
//a.Register([] (int, double) { return true; });
// works
a.Register(foo);
// doesn't
//a.Register(foo2);
}
क्या आप एक समान हस्ताक्षर, या संगत हस्ताक्षर चाहते हैं? उदाहरण के लिए, यदि आपका हस्ताक्षर 'बूल() 'है, तो क्या आप' int (*)()', यानी फ़ंक्शन पॉइंटर को कोई तर्क लेने और पूर्णांक लौटने के लिए स्वीकार करेंगे? पूर्णांक बूल को निहित रूप से परिवर्तित करेगा ताकि यह संगत हो, लेकिन यह समान नहीं है। –
यह एक अच्छा सवाल है - मैं जितना संभव हो उतना मजबूत टाइपिंग करना पसंद करूंगा, इसलिए मेरे उपयोग के मामले में इस मामले में int (*)() को अस्वीकार करना बेहतर होगा। – pzelasko