2012-01-28 24 views
15

यह कुछ हफ्ते पहले काम करता था:सी ++ 11 constexpr समारोह के तर्क टेम्पलेट दिया गया तर्क

template <typename T, T t> 
T   tfunc() 
{ 
    return t + 10; 
} 

template <typename T> 
constexpr T  func(T t) 
{ 
    return tfunc<T, t>(); 
} 

int main() 
{ 
    std::cout << func(10) << std::endl; 
    return 0; 
} 

लेकिन अब g++ -std=c++0x का कहना है:

main.cpp: In function ‘constexpr T func(T) [with T = int]’: 
main.cpp:29:25: instantiated from here 
main.cpp:24:24: error: no matching function for call to ‘tfunc()’ 
main.cpp:24:24: note: candidate is: 
main.cpp:16:14: note: template<class T, T t> T tfunc() 
main.cpp:25:1: warning: control reaches end of non-void function [-Wreturn-type] 

clang++ -std=c++11 का कहना है कि tfunc<T, t>() के खाके की मापदंडों अनदेखी कर रहे हैं क्योंकि अमान्य।

क्या यह एक बग है, या एक फिक्स?

पुनश्च:

g++ --version =>g++ (GCC) 4.6.2 20120120 (prerelease)

clang++ --version =>clang version 3.0 (tags/RELEASE_30/final) (3.0.1)

+0

एफडब्ल्यूआईडब्ल्यू, क्लैंग 3.1 हेड भी वही त्रुटियों को फैलाता है। – Xeo

उत्तर

7

पैरामीटर t एक निरंतर अभिव्यक्ति नहीं है। इसलिए त्रुटि। यह भी ध्यान दिया जाना चाहिए कि यह निरंतर अभिव्यक्ति नहीं हो सकता है।

आप लगातार अभिव्यक्ति को तर्क के रूप में पारित कर सकते हैं, लेकिन फ़ंक्शन के अंदर, ऑब्जेक्ट (पैरामीटर) जो मान रखता है, निरंतर अभिव्यक्ति नहीं है।

t के बाद से, एक निरंतर अभिव्यक्ति नहीं है, यह टेम्पलेट तर्क के रूप में नहीं किया जा सकता है:

template <typename T, T t> 
T tfunc() 
{ 
    return t + 10; 
} 

template <typename T, T t> //<---- t became template argument! 
constexpr T func() 
{ 
    return tfunc<T, t>(); 
} 

#define FUNC(a) func<decltype(a),a>() 

int main() 
{ 
    std::cout << FUNC(10) << std::endl; 
} 

अब यह काम करना चाहिए:

return tfunc<T, t>(); //the second argument must be a constant expression 

हो सकता है, आप कुछ इस तरह हैं: online demo

+0

मैं अभी भी वाक्य से उलझन में हूं: * किसी फ़ंक्शन के लिए तर्क एक कॉन्स्ट एक्सप्रेशन नहीं हो सकता है * –

+0

@ श्री अनीबिस: यही कारण है कि मैंने अगले पैरा में उस भाग को समझाया। क्या तुमने इसे पढ़ा? – Nawaz

+0

आपका मतलब '..func (टी टी)' 'func' के अंदर,' t' constexp में नहीं है, है ना? –

1

ऐसा लगता है कि इसे एक त्रुटि देना चाहिए - इसका कोई तरीका नहीं है यह जानकर कि आप निरंतर मान में फंस गए हैं जैसे कि func।

अधिक आम तौर पर, आप रनटाइम मानों को टेम्पलेट तर्क के रूप में उपयोग नहीं कर सकते हैं। टेम्पलेट स्वाभाविक रूप से एक संकलन समय निर्माण कर रहे हैं।

+2

और 'constexpr' कार्यों का संकलन समय पर मूल्यांकन किया जा सकता है। – Xeo

+3

@Xeo मुझे इस उत्तर में आपकी टिप्पणी की प्रासंगिकता दिखाई नहीं दे रही है। ऐसा लगता है, मैं कहता हूं "मेरे हाथ का उपयोग घूमने के लिए नहीं किया जा सकता है।" और आप कहते हैं "और आपकी बांह का उपयोग आपके हाथ को स्थानांतरित करने के लिए किया जा सकता है।" –

+0

अनुरूपता पर rofl: डी –

2

मुझे यह महसूस हो रहा है कि constexpr को 'रनटाइम' संदर्भ में भी वैध होना चाहिए, न केवल संकलन-समय पर। constexpr के रूप में फ़ंक्शन को चिह्नित करने से कंपाइलर को संकलन-समय पर इसका मूल्यांकन करने का प्रयास करने के लिए प्रोत्साहित किया जाता है, लेकिन फ़ंक्शन में अभी भी वैध रन-टाइम कार्यान्वयन होना चाहिए।

अभ्यास में, इसका मतलब संकलक कैसे कार्यावधि में इस समारोह को लागू करने नहीं जानता है कि:

template <typename T> 
constexpr T  func(T t) 
{ 
    return tfunc<T, t>(); 
} 

का संभावित हल निर्माता को बदलने के लिए ऐसी है कि यह एक सामान्य पैरामीटर के रूप में अपने t पैरामीटर लेता है, नहीं टेम्पलेट पैरामीटर के रूप में, और निर्माता के रूप में चिह्नित constexpr:

:

template <typename T> 
constexpr T  tfunc(T t) 
{ 
    return t + 10; 
} 
template <typename T> 
constexpr T  func(T t) 
{ 
    return tfunc<T>(t); 
} 

'निरंतर अभिव्यक्ति सत्ता' के तीन स्तर हैं

  1. टेम्पलेट पूर्णांक पैरामीटर या (गैर VLA) सरणी आकार // कुछ ऐसा एक निरंतर अभिव्यक्ति होना चाहिए
  2. constexpr // कुछ ऐसा एक निरंतर अभिव्यक्ति
  3. गैर निरंतर हो सकता है -expression

आप उस सूची में उस सूची में कम से कम कुछ आइटमों को वास्तव में परिवर्तित नहीं कर सकते हैं, लेकिन स्पष्ट रूप से यह अन्य मार्ग संभव है।

उदाहरण के लिए, इस समारोह

constexpr int foo(int x) { return x+1; } 

के लिए एक कॉल जरूरी एक निरंतर अभिव्यक्ति नहीं है।

// g++-4.6 used in these few lines. ideone doesn't like this code. I don't know why 
int array[foo(3)]; // this is OK 
int c = getchar(); 
int array[foo(c)]; // this will not compile (without VLAs) 

तो एक constexpr समारोह से लौटने के मूल्य स्थिर अभिव्यक्ति केवल अगर सभी मापदंडों, और समारोह के कार्यान्वयन है, पर संकलन समय पर क्रियान्वित पूरा किया जा सकता।

+0

'constexpr int i = something_that_MUST_be_a_constexpr;' – Xeo

+0

@Xeo, यह * कम से कम * एक 'constexpr' होना चाहिए। जबकि 'टेम्पलेट संरचना एक्स; एक्स एक्स; 'की आवश्यकता है कि' मैं 'constexpr' से भी अधिक हो। –

+0

हो सकता है कि मुझे 'निरंतर अभिव्यक्ति' के लिए एक छोटे हाथ के रूप में दूसरे 'constexpr' का उपयोग नहीं करना चाहिए था ... :) मैं बस कहना चाहता था कि' constexpr' के लिए, कभी-कभी कुछ * एक निरंतर अभिव्यक्ति होना चाहिए - जब एक चर के रूप में घोषित किया जाता है। (आपके "' constexpr' // के उत्तर के रूप में कुछ * जो * निरंतर अभिव्यक्ति हो सकता है "। – Xeo

2

प्रश्न दोबारा दोहराएं: आपके पास दो कार्य हैं जो T प्रकार का पैरामीटर लेते हैं। कोई अपना पैरामीटर टेम्पलेट पैरामीटर के रूप में लेता है, और दूसरा 'सामान्य' पैरामीटर के रूप में लेता है। मैं tfunc और func के बजाय दो फ़ंक्शन funcT और funcN पर कॉल करने जा रहा हूं। आप funcN से funcT पर कॉल करने में सक्षम होना चाहते हैं। उत्तरार्द्ध को constexpr के रूप में चिह्नित करने से मदद नहीं मिलती है।

constexpr के रूप में चिह्नित कोई भी फ़ंक्शन संकलित करने योग्य होना चाहिए जैसे कि constexpr वहां नहीं था। constexpr फ़ंक्शंस एक छोटे से स्किज़ोफ्रेनिक हैं। वे केवल कुछ परिस्थितियों में पूर्ण निरंतर अभिव्यक्ति के लिए स्नातक हैं।

यह funcN लागू करने के लिए एक सरल तरीके से रन टाइम पर चलाने के लिए, के रूप में यह टी की सभी संभव मूल्यों के लिए काम करने के लिए सक्षम होने के लिए की आवश्यकता होगी संभव नहीं होगा। इसके लिए कंपाइलर को tfunc के कई उदाहरणों को तत्काल करने की आवश्यकता होगी, एक टी के प्रत्येक मान के लिए। लेकिन यदि आप टी के एक छोटे से सबसेट के साथ रहने के इच्छुक हैं तो आप इसके आसपास काम कर सकते हैं।ग्राम में ++ 1024 के एक टेम्पलेट प्रत्यावर्तन सीमा नहीं है, ताकि आप आसानी से इस कोड के साथ टी के 1024 के मानों का प्रबंधन कर सकते हैं:

#include<iostream> 
#include<functional> 
#include<array> 
using namespace std; 

template <typename T, T t> 
constexpr T funcT() { 
     return t + 10; 
} 

template<typename T, T u> 
constexpr T worker (T t) { 
     return t==0 ? funcT<T,u>() : worker<T, u+1>(t-1); 

} 
template<> 
constexpr int worker<int,1000> (int) { 
      return -1; 
} 


template <typename T> 
constexpr T  funcN(T t) 
{ 
     return t<1000 ? worker<T,0>(t) : -1; 
} 

int main() 
{ 
    std::cout << funcN(10) << std::endl; 
    array<int, funcN(10)> a; // to verify that funcN(10) returns a constant-expression 
    return 0; 
} 

यह एक समारोह worker जो रिकर्सिवली किसी टेम्प्लेट में 'सामान्य' पैरामीटर t में परिवर्तित कर देंगे का उपयोग करता है पैरामीटर u, जो तब यह tfunc<T,u> को तत्काल और निष्पादित करने के लिए उपयोग करता है।

महत्वपूर्ण लाइन return funcT<T,u>() : worker<T, u+1>(t-1);

यह सीमाएँ हैं है। यदि आप long, या अन्य अभिन्न प्रकारों का उपयोग करना चाहते हैं, तो आपको एक और विशेषज्ञता जोड़नी होगी। जाहिर है, यह कोड केवल 0 और 1000 के बीच टी के लिए काम करता है - सटीक ऊपरी सीमा शायद संकलक-निर्भर है। एक अन्य विकल्प 2 में से प्रत्येक बिजली के लिए एक अलग कार्यकर्ता समारोह के साथ, एक तरह के द्विआधारी खोज का उपयोग हो सकता है:

template<typename T, T u> 
constexpr T worker4096 (T t) { 
     return t>=4096 ? worker2048<T, u+4096>(t-4096) : worker2048<T, u>(t); 

} 

मुझे लगता है कि इस टेम्पलेट-प्रत्यावर्तन सीमा के आसपास काम करेंगे, लेकिन यह अभी भी एक बहुत की आवश्यकता होगी बड़ी संख्या में तत्कालताएं और संकलन बहुत धीमा कर देगा, अगर यह बिल्कुल काम करता है।

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