2011-11-12 19 views
23

मैं उपयोगकर्ता परिभाषित अक्षर का परीक्षण कर रहा हूं। मैं _fac संख्या के फैक्टोरियल को वापस करना चाहता हूं।उपयोगकर्ता परिभाषित शाब्दिक तर्क constexpr नहीं हैं?

इसे constexpr फ़ंक्शन काम करने के बाद, हालांकि यह मुझे टेम्पलेट्स के साथ ऐसा करने नहीं देता है क्योंकि संकलक शिकायत करता है कि तर्क constexpr नहीं हो सकते हैं।

मैं इस से उलझन में हूं - सचमुच निरंतर अभिव्यक्ति नहीं हैं? 55_fac में हमेशा एक शाब्दिक है जिसका संकलन समय के दौरान मूल्यांकन किया जा सकता है, तो मैं इसका उपयोग क्यों नहीं कर सकता?

सबसे पहले विधि:

constexpr int factorial_function(int x) { 
    return (x > 0) ? x * factorial_function(x - 1) : 1; 
} 

constexpr int operator "" _fac(unsigned long long x) { 
    return factorial_function(x); // this works 
} 

दूसरी विधि:

template <int N> struct factorial_template { 
    static const unsigned int value = N * factorial_template<N - 1>::value; 
}; 
template <> struct factorial_template<0> { 
    static const unsigned int value = 1; 
}; 

constexpr int operator "" _fac(unsigned long long x) { 
    return factorial_template<x>::value; // doesn't work - x is not a constexpr 
} 
+0

मुझे नहीं लगता कि कोई संकलक अभी तक उन उपयोगकर्ता परिभाषित अक्षरों को लागू करता है। आप इसका परीक्षण कैसे कर रहे हैं? –

+0

@KerrekSB जीसीसी 4.7 स्नैपशॉट – Pubby

+0

अच्छा! मुझे नहीं पता था कि अभी तक समर्थित था। मेरे पास मशीन पर कहीं भी इंस्टॉल किया गया है, अब मैं उन वैरैडिक टेम्पलेट्स को काम करने के लिए प्रेरित हूं :-) –

उत्तर

3

यह है कि कैसे मैं यह कर समाप्त हो गया है:

KerrekSB को
template <typename t> 
constexpr t pow(t base, int exp) { 
    return (exp > 0) ? base * pow(base, exp-1) : 1; 
}; 

template <char...> struct literal; 
template <> struct literal<> { 
    static const unsigned int to_int = 0; 
}; 
template <char c, char ...cv> struct literal<c, cv...> { 
    static const unsigned int to_int = (c - '0') * pow(10, sizeof...(cv)) + literal<cv...>::to_int; 
}; 

template <int N> struct factorial { 
    static const unsigned int value = N * factorial<N - 1>::value; 
}; 
template <> struct factorial<0> { 
    static const unsigned int value = 1; 
}; 

template <char ...cv> 
constexpr unsigned int operator "" _fac() 
{ 
    return factorial<literal<cv...>::to_int>::value; 
} 

विशाल धन्यवाद!

+0

डाउनवॉटिंग, क्योंकि उत्तर वास्तव में ओपी के प्रश्नों का उत्तर नहीं देता है, लेकिन केवल कोड शामिल है। – jotik

3

आदेश उपयोगकर्ता परिभाषित शाब्दिक साथ constexpr का उपयोग करने के अलावा, आप जाहिरा तौर पर एक variadic टेम्पलेट का उपयोग करने के लिए है। उदाहरण के लिए wikipedia article में दूसरी लिस्टिंग पर नज़र डालें।

+0

आपको हमेशा 'constexpr' का उपयोग करने के लिए वैरैडिक टेम्पलेट्स का उपयोग नहीं करना पड़ता है, लेकिन इस मामले में इसकी आवश्यकता होती है (लेकिन मैं जानता हूँ कि आपका मतलब क्या है)। –

+0

मैं 'char' के' vari' में एक भिन्न टेम्पलेट कैसे बदल सकता हूं? – Pubby

+0

@ सेठ कार्नेगी: – Nate

3

मैं गलत हो सकता हूं, लेकिन मुझे लगता है कि कॉन्टेक्सप्रस कार्यों को गैर-निरंतर तर्कों के साथ भी बुलाया जा सकता है (इस मामले में वे लगातार अभिव्यक्ति नहीं देते हैं और रनटाइम पर मूल्यांकन किए जाते हैं)। जो गैर-प्रकार के टेम्पलेट तर्कों के साथ अच्छी तरह से काम नहीं करेगा।

+0

ठीक है, संभवतः, संकलक शिकायत करेगा अगर आपने फ़ंक्शन में एक गैर-संकलन-समय-निरंतर पारित किया है। क्या यह समस्या हल करने का एक तरीका हो सकता है जहां टेम्पलेट-नेस कोड की परतों की सभी तरह की चाल चलती है? –

+0

@ माइकलप्रिस: बेशक यह कॉन्स्टेक्स कार्यों में गैर-कॉन्स एक्सप्रेशन पास करने के बारे में शिकायत कर सकता है (और जैसा कि मैंने कहा, मुझे यकीन नहीं है कि मैं सही हूं)। लेकिन इसका मतलब यह होगा कि आपको आमतौर पर दो कार्यों की आवश्यकता होती है जो 'constexpr' कीवर्ड को छोड़कर, निरंतर अभिव्यक्तियों के लिए एक और अन्य सभी अभिव्यक्तियों के लिए एक जैसी होती हैं। – celtschk

1

@ पब्बी। चार गैर-प्रकार पैरामीटर पैक को पचाने का आसान तरीका यह है कि इसे स्ट्रिंग के लिए प्रारंभकर्ता सूची में कैचर करें। फिर आप atoi, atof, आदि का उपयोग कर सकते हैं:

#include <iostream> 

template<char... Chars> 
    int 
    operator "" _suffix() 
    { 
    const char str[]{Chars..., '\0'}; 
    return atoi(str); 
    } 

int 
main() 
{ 
    std::cout << 12345_suffix << std::endl; 
} 

सी-शैली कार्यों के लिए एक शून्य चरित्र पर ध्यान देना याद रखें।

+0

इसके साथ समस्या यह है कि यह 'constexpr' नहीं है। यह तर्क प्रकार के रूप में 'हस्ताक्षरित लंबे समय तक' गुजरने से वास्तव में बदतर है। – Pubby

8

मैं वहाँ सी ++ 11 में एक बेहतर तरीका वर्तमान स्वीकृत जवाब से यह करने के लिए है, तो पता नहीं है, लेकिन आराम constexpr में सी ++ 14, तुम बस "सामान्य" कोड लिख सकते हैं साथ:

constexpr unsigned long long int operator "" _fac(unsigned long long int x) { 
    unsigned long long int result = 1; 
    for (; x >= 2; --x) { 
     result *= x; 
    } 
    return result; 
} 

static_assert(5_fac == 120, "!"); 
संबंधित मुद्दे