2015-02-13 9 views
14

क्या फ़ंक्शन के तर्कों के प्रकार प्राप्त करने और टेम्पलेट पैरामीटर पैक के रूप में इन प्रकारों को पार करने का कोई मानक तरीका है? मुझे पता है कि यह सी ++ में संभव है क्योंकि it has been done beforeसी ++ फ़ंक्शन पैरामीटर के प्रकार प्राप्त करें

मुझे उम्मीद थी कि सी ++ 14 या आगामी सी ++ 1Z के साथ, वहाँ arg_types<F>... यहाँ लागू करने के लिए एक मुहावरेदार तरीका होगा:

template <typename ...Params> 
void some_function(); // Params = const char* and const char* 

FILE* fopen(const char* restrict filename, const char* restrict mode); 

int main(){ 
    some_function<arg_types<fopen>...>(); 
} 

बस, स्पष्ट होना एक जवाब का दावा है कि वहाँ ऐसा करने का कोई मानक तरीका जवाब नहीं है। यदि कोई जवाब नहीं है, तो मैं यह पसंद करूंगा कि प्रश्न तब तक अनुत्तरित रहेगा जब तक समाधान सी ++ 500 में या ब्रह्मांड की गर्मी की मृत्यु तक नहीं जोड़ा जाता है, जो भी पहले होता है :)

संपादित करें: एक हटाए गए उत्तर ने नोट किया कि मैं पैरामीटर प्रकारों के नाम प्राप्त करने के लिए PRETTY_FUNCTION का उपयोग कर सकते हैं। हालांकि, मैं वास्तविक प्रकार चाहता हूं। उन प्रकार के नाम नहीं।

+0

आप एक अविस्तारित पैरामीटर पैक के बिना पैक विस्तार नहीं कर सकता है, ताकि वाक्य रचना सवाल से बाहर है। – Columbo

+1

क्या आप प्रतिबिंब के कुछ रूपों के बारे में बात कर रहे हैं? आप नाम मैंगलिंग पर एक नज़र डाल सकते हैं: क्योंकि सी ++ बाइनरी पर डीबग जानकारी तक पहुंचने और फ़ंक्शन पता जानने के द्वारा तर्क में तर्क प्रकार को एन्कोड करता है, आप पैरामीटर प्रकार क्या हैं ... –

+1

1. फ़ाइल के साथ सी ++ का उपयोग करना ?! ! 2. रन टाइम –

उत्तर

8

यह वाक्यविन्यास थोड़ा अलग है।

सबसे पहले, क्योंकि पैक पैक के साथ काम करना आसान होता है, एक प्रकार जिसमें एक पैक होता है।

template<class...>struct types{using type=types;}; 

यहाँ workhorse है: using type=types; बस मुझे कोड है कि एक types उत्पन्न करता है में काम बचाता है। यह एक हस्ताक्षर लेता है, और हस्ताक्षर के लिए तर्क युक्त types<?...> बंडल का उत्पादन करता है। 3 कदम इसलिए हम अच्छे साफ सी ++ 14esque वाक्यविन्यास प्राप्त कर सकते हैं:

template<class Sig> struct args; 
template<class R, class...Args> 
struct args<R(Args...)>:types<Args...>{}; 
template<class Sig> using args_t=typename args<Sig>::type; 

यहां एक वाक्यविन्यास अंतर है। सीधे Params... लेने के बजाय, हम types<Params...> लेते हैं। ,

template <class...Params> 
void some_function(types<Params...>) { 
} 

मेरे fopen अलग है क्योंकि मैं सामान ing #include परेशान करने के लिए नहीं करना चाहते हैं: यह "टैग भेजने" पैटर्न, जहां हम शोषण प्रकार सूची में बहस स्थानांतरित करने के लिए टेम्पलेट समारोह प्रकार कटौती के समान है:

void* fopen(const char* filename, const char* mode); 

और वाक्य रचना fopen के आधार पर नहीं है, बल्कि प्रकार fopen की। यदि आपके पास पॉइंटर है, तो आपको decltype(*func_ptr) या somesuch करना होगा। या हम उपयोग में आसानी के लिए R(*)(Args...) को संभालने के लिए शीर्ष बढ़ाने सकता है:

int main(){ 
    some_function(args_t<decltype(fopen)>{}); 
} 

live example

नोट करता अतिभारित कार्यों के साथ काम नहीं कि, न ही यह समारोह वस्तुओं के साथ काम करता है।

सामान्य रूप से, इस तरह की बात एक बुरा विचार है, क्योंकि आमतौर पर आप जानते हैं कि आप किसी ऑब्जेक्ट के साथ कैसे बातचीत कर रहे हैं।

उपर्युक्त केवल तभी उपयोगी होगा यदि आप कोई फ़ंक्शन (या फ़ंक्शन पॉइंटर) लेना चाहते थे और कहीं कुछ स्टैक से कुछ तर्कों को पॉप करते हैं और इसे अपेक्षित पैरामीटर के आधार पर कॉल करते हैं, या कुछ इसी तरह के होते हैं।

+1

"कुछ स्टैक से कहीं कुछ तर्क पॉप करें और इसे अपेक्षित पैरामीटर के आधार पर कॉल करें"। हू, यह वही है जो मैं कर रहा हूँ! – Navin

+1

@Navin तब भी, मैं लगभग इस तरह के "इस वापसी मूल्य की उम्मीद कर रहे इस प्रकार का उपयोग करके इस समारोह को आमंत्रित करता हूं" - यानी, हस्ताक्षर स्वतंत्र रूप से पास करें। आप दोबारा जांच कर सकते हैं कि हस्ताक्षर * कार्य * आमंत्रण लक्ष्य के साथ * काम करता है। चट्टानों को अधिभारित करना, और अधिभार खोना * और * एडीएल बेकार है। ओह, और यदि आप 'some_function' में फ़ंक्शन पॉइंटर पास कर रहे हैं, तो आप इसे सीधे' Args ... 'से घटा सकते हैं। – Yakk

+0

ओवरलोडिंग और एडीएल खोना चूसता है, लेकिन मैं इसका उपयोग सी फंक्शंस जैसे 'fopen() 'के लिए कर रहा हूं। मुझे शुभकामनाएँ दें। – Navin

2

Boost.FunctionTypes और std::index_sequence का उपयोग करें। नीचे एक उदाहरण है जो फ़ंक्शन func के तर्क प्रकारों को प्रिंट करता है।आप जो चाहते हैं उसे करने के लिए आप doit स्थैतिक फ़ंक्शन को बदल सकते हैं। इसे क्रिया here में देखें।

template <typename FuncType> 
using Arity = boost::function_types::function_arity<FuncType>; 

template <typename FuncType> 
using ResultType = typename boost::function_types::result_type<FuncType>::type; 

template <typename FuncType, size_t ArgIndex> 
using ArgType = typename boost::mpl::at_c<boost::function_types::parameter_types<FuncType>, ArgIndex>::type; 

void func(int, char, double) {} 

template <typename Func, typename IndexSeq> 
struct ArgPrintHelper; 

template <typename Func, size_t... Inds> 
struct ArgPrintHelper<Func, integer_sequence<size_t, Inds...> > 
{ 
    static void doit() 
    { 
    string typeNames[] = {typeid(ResultType<Arg>).name(), typeid(ArgType<Func, Inds>).name()...}; 
    for (auto const& name : typeNames) 
     cout << name << " "; 
    cout << endl; 
    } 
}; 

template <typename Func> 
void ArgPrinter(Func f) 
{ 
    ArgPrintHelper<Func, make_index_sequence<Arity<Func>::value> >::doit(); 
} 

int main() 
{ 
    ArgPrinter(func); 
    return 0; 
} 

हेडर (यहाँ नीचे ले जाया ऊपर कोड स्निपेट में शोर को कम करने):

#include <boost/function_types/function_type.hpp> 
#include <boost/function_types/parameter_types.hpp> 
#include <boost/function_types/result_type.hpp> 
#include <boost/function_types/function_arity.hpp> 

#include <algorithm> 
#include <iostream> 
#include <string> 
#include <type_traits> 
#include <typeinfo> 
#include <tuple> 
#include <utility> 
using namespace std; 
+4

Boost.TypeIndex में भी फेंको और आपको एक बहुत ही पठनीय परिणाम मिलता है - http://coliru.stacked-crooked.com/a/d9af42b0a48dc867 – Praetorian

संबंधित मुद्दे