मैं C ++ को दूसरे टेम्प्लेट तर्क का अनुमान लगाने से कैसे रोक सकता हूं?


26

मैं एक C ++ लाइब्रेरी ( strf ) का उपयोग कर रहा हूं , जो कहीं न कहीं, इसके भीतर निम्नलिखित कोड है:

namespace strf {
template <typename ForwardIt>
inline auto range(ForwardIt begin, ForwardIt end) { /* ... */ }

template <typename Range, typename CharT>
inline auto range(const Range& range, const CharT* sep) { /* ... */ }
}

अब, मैं strf::range<const char*>(some_char_ptr, some_char_ptr + some_length)अपने कोड में उपयोग करना चाहता हूं। लेकिन अगर मैं ऐसा करता हूं, तो मुझे निम्नलिखित त्रुटि मिलती है (CUDA 10.1 के NVCC के साथ):

error: more than one instance of overloaded function "strf::range" matches the argument list:
            function template "auto strf::range(ForwardIt, ForwardIt)"
            function template "auto strf::range(const Range &, const CharT *)"
            argument types are: (util::constexpr_string::const_iterator, util::constexpr_string::const_iterator)

इससे बचने के लिए लाइब्रेरी कोड को संभवतः बदला जा सकता है (उदाहरण के लिए:

inline auto range(const typename std::enable_if<not std::is_pointer<typename std::remove_cv<Range>::type>::value, Range &>::type range, const CharT* sep)

सुनिश्चित करने के लिए Rangeएक सूचक नहीं है); लेकिन मैं अभी उस बदलाव को नहीं कर सकता। इसके बजाय, मैं किसी भी तरह संकलक को इंगित करना चाहता हूं कि मैं वास्तव में केवल एक टेम्पलेट तर्क का मतलब रखता हूं, एक निर्दिष्ट नहीं और दूसरा एक घटाया हुआ।

क्या मै वह कर सकता हूं?

C ++ 11 और C ++ 14 के उत्तर की सराहना करेंगे; कटौती गाइड से जुड़े सी ++ 17 जवाब कम प्रासंगिक हैं लेकिन अगर आपके पास एक है, तो कृपया इसे पोस्ट करें (भविष्य के एनवीसीसी संस्करणों के लिए ...)


अद्यतन: इस स्थिति को दरकिनार करने के लिए strf लाइब्रेरी को ही अपडेट किया गया है, लेकिन सवाल जैसा पूछा गया है।


1
मुझे लगता है कि एक कस्टम पुनरावृत्ति पास करने का अनुमान है जो पतले लपेटता है char*लेकिन क्या कोई एक समाधान नहीं है?
कोनराड रुडोल्फ

1
@KonradRudolph: यह एक वर्कअराउंड है, लेकिन मेरे सवाल का जवाब नहीं देता है। मेरे पास वास्तव में पहले से ही एक और वर्कअराउंड है (/ /...*/ में क्या है इसके लिए विशिष्ट), लेकिन मैं यहां हाई रोड लेना चाहूंगा।
ईनपोकलम

1
उस स्थिति में मेरा (अनुमान) उत्तर "नहीं किया जा सकता है", दुर्भाग्य से। निष्पक्ष होने के लिए मुझे यकीन नहीं है कि मैं अपने सुझाए गए वर्कअराउंड को अपने कोड में स्वीकार करूंगा।
कोनराड रुडोल्फ

बस स्पष्ट करने के लिए: क्या आप एक सामान्य समाधान चाहते हैं, जो हमेशा एक बनाम दो मापदंडों के साथ टेम्पलेट ओवरलोड के बीच कॉल को अंतर करने के लिए काम करेगा या क्या आप इस मामले के लिए केवल एक समाधान चाहते हैं?
अखरोट

@ अखरोट: सामान्य समाधान बेहतर होगा; मेरा विशिष्ट परिदृश्य समस्या के लिए ज्यादातर प्रेरणा है।
einpoklum

जवाबों:


16
template<typename T>
inline constexpr auto range1_ptr = strf::range<T>;

template<typename T>
inline decltype(auto) range1(T begin, T end) {
    return range1_ptr<T>(begin, end);
}

इसके range1बजाय कॉल करें strf::range

range1_ptr<T>(...)हमेशा एक टेम्पलेट तर्क लेने वाले टेम्पलेट को स्पष्ट रूप से कॉल करने के लिए उपयोग किया जा सकता है, लेकिन तर्कों से कोई कटौती नहीं करता है। range1मूल strf::rangeटेम्पलेट से कटौती की नकल करता है ।

यह काम करता है, क्योंकि [temp.deduct.funcaddr] / 1 का कहना है कि लक्ष्य प्रकार के रूपांतरण के बिना किसी फ़ंक्शन का पता लेने पर टेम्पलेट तर्क में कटौती प्रत्येक उम्मीदवार फ़ंक्शन टेम्पलेट पर की जाती है जैसे कि एक काल्पनिक कॉल के पैरामीटर और तर्क सूची थे खाली करें। तो दूसरे टेम्पलेट तर्क को दो टेम्पलेट मापदंडों के साथ दूसरे अधिभार के लिए नहीं घटाया जा सकता है। एकमात्र उम्मीदवार छोड़ा गया पहला अधिभार है, जिसे फ़ंक्शन पॉइंटर के लक्ष्य के रूप में चुना जाएगा।

जब तक कोई दूसरा उम्मीदवार फ़ंक्शन टेम्प्लेट न हो, जिसके लिए केवल एक तर्क के साथ एक वैध टेम्प्लेट-आईडी बनाई जा सकती है, range1_ptrहमेशा फ़ंक्शन टेम्पलेट को एक तर्क से बिना किसी तर्क के कॉल करने के लिए उपयोग किया जा सकता है। अन्यथा, तात्कालिकता range1_ptrअस्पष्टता के कारण एक त्रुटि देगी।


क्या इसमें अस्पष्टता नहीं होगी strf::range<T>?
einpoklum

1
@einpoklum यह जीसीसी और क्लैंग पर ठीक संकलन करता है। मैंने मानक की जांच नहीं की, लेकिन आश्चर्य होगा कि क्या इसे अस्पष्ट माना जाता है।
अखरोट

शायद आपको फ़ंक्शन का नाम बदलना चाहिए pretty_please_with_sugar_on_top()? ... C ++ कभी-कभी इतनी अजीब हो सकती है ...
einpoklum

आप स्वीकृत उत्तर को
अस्वीकार

11

क्या गुजर रहा है using?

using tfp = void(*)(char const *, char const *);

tfp x = &strf::range;

char const * a = "abcd";

(*x)(a, a+2);

और यह संकलन? दूसरी पंक्ति विशेष रूप से संदिग्ध लगती है।
ईनपोकलम

@einpoklum - अजीब बात है, है ना?
अधिकतम ६६

@einpoklum - दुर्भाग्य से एक सामान्य समाधान नहीं है; इस मामले में काम करता है क्योंकि (अगर मैं गलत नहीं हूं) केवल पहला range()संस्करण ही संगत है tpf; अन्य मामला अलग हो सकता है।
अधिकतम ६६

@einpoklum - दूसरी पंक्ति में आप टेम्पलेट पैरामीटर भी खोज सकते हैं ( tfp x = &strf::range<char const *>;); इस तरह से मुझे लगता है कि आपके पास एक सामान्य उपाय है, जो अखरोट के एक के बराबर है
अधिकतम

0

एक समाधान है

1) सबसे पहले, आपको दूसरे तर्क के लिए प्रकार निर्दिष्ट करना चाहिए, जैसे (char *)(some_char_ptr + some_length)

2) constदोनों के लिए उपयोग न करें , यह अच्छी तरह से काम करता है:

strf::range((char *)some_char_ptr, (char *)(some_char_ptr + some_length));

आप को बदलने के लिए कोशिश कर सकते हैं (char *)के साथ (const char *)छोड़ दिया पर या दाएँ भाग में, यह अभी भी काम करता है।


यह बहुत बदसूरत है अगर तर्क constडेटा पर इंगित करते हैं।
एस्केलर

1. कोई दूसरा तर्क नहीं है। मुझे एकल-तर्क टेम्पलेट चाहिए। 2. दिलचस्प हैक! पहले सुझाव के लिए -1 और दूसरे के लिए +1 :-P
einpoklum
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.