अस्पष्ट ओवरलोड टेम्पलेट


16

मेरे पास निम्न अस्थायी कोड है

#include <vector>
#include <array>
#include <iostream>

template<typename T1>
void foo(std::vector<T1> bar) {
    std::cout << "GENERIC" << std::endl;
}

template<typename T1>
void foo(std::vector<std::vector<T1>> bar) {
    std::cout << "SPECIFIC (vector)" << std::endl;
}

template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

int main() {
    std::vector<std::vector<int>> a(2, std::vector<int> { 1, 2, 3});
    std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});

    foo(a);
    foo(b);
}

जो पैदा करता है

SPECIFIC (vector)
GENERIC

मैं सोच रहा हूं कि वेक्टर-ऑफ-वेक्टर संस्करण को विशिष्ट टेम्पलेट के साथ क्यों कहा जाता है, लेकिन वेक्टर-ऑफ-सरणी संस्करण को जेनेरिक के साथ कहा जाता है?


2
FYI करें: आप इसे सरल बना सकते हैं, एक ही मुद्दे के साथ, vectorउन सभी पर बाहरी को हटाकर । यहां देखें
क्रिसमिड

@ क्रिसमम अच्छी पकड़। यह उदाहरण मेरे उत्पादन कोड से संश्लेषित किया गया था, जहां नेस्टेड संरचना आवश्यक है।
Xaser

5
MSVC वेक्टर-ऑफ-एरेज़ संस्करण कहता है: godbolt.org/z/7Gfeb0
R2RT

जवाबों:


8
template<typename T1, size_t SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

आपको std::size_tइसके बजाय उपयोग करना चाहिए intयहाँ भागो

संपादित करें: वास्तव में, आपकी टिप्पणियों और कोड के बारे में मेरे अंतर्ज्ञान ने मुझे विषय में खुदाई करने के लिए प्रेरित किया। पहली नज़र में, एक मानक डेवलपर (मेरे जैसे) उम्मीद परिवर्तित करने के लिए संकलक intकरने के लिए std::size_t(क्योंकि वे दोनों अभिन्न प्रकार के होते हैं और परोक्ष परिवर्तित बहुत मामूली बात है) स्पर्श करें और void foo(std::vector<std::array<T1, SIZE>> bar)सबसे अच्छा विशेषज्ञता के रूप में। तो टेम्पलेट तर्क कटौती पृष्ठ पढ़ते समय मुझे यह मिला:

यदि पैरामीटर सूची में एक गैर-प्रकार टेम्पलेट पैरामीटर का उपयोग किया जाता है, और संबंधित टेम्पलेट तर्क को घटाया जाता है, तो घटा हुआ टेम्पलेट तर्क का प्रकार (जैसा कि इसकी एन्कोडिंग टेम्पलेट पैरामीटर सूची में निर्दिष्ट किया गया है, जिसका अर्थ है कि संदर्भ संरक्षित हैं) का प्रकार से मेल खाना चाहिए गैर-टाइप टेम्पलेट पैरामीटर बिल्कुल, सिवाय इसके कि सीवी-क्वालीफायर को छोड़ दिया जाता है, और जहां टेम्पलेट तर्क को एक सरणी बाउंड से घटाया जाता है - उस मामले में किसी भी अभिन्न प्रकार की अनुमति है, भले ही यह हमेशा सच हो जाए:

हमेशा की तरह, निश्चित रूप से, आपको यह समझने के लिए एक बार से कुछ अधिक बार पढ़ना चाहिए कि इसका क्या मतलब है :)

तो एक दिलचस्प परिणाम सामने आता है।

पहले से ही हमारी वांछित विशेषज्ञता का चयन नहीं किया गया है, लेकिन यदि कंपाइलर को चुनने के लिए मजबूर किया गया था, तो यह एक त्रुटि होगी।

template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

int main() {
    std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});

    foo(b); // P = std::vector<std::array<int,(int)SIZE>
            // A = std::vector<std::array<int,(unsigned_long)SIZE>>
            // error: deduced non-type template argument does not have the same
            // type as its corresponding template argument */
}

कोड चलाएं

एक और दिलचस्प बात है:

यदि गैर-प्रकार के टेम्पलेट तर्क को घटाया नहीं गया था, तो कोई प्रतिबंध नहीं होगा जो तर्क और टेम्पलेट प्रकारों को समान करने के लिए बाध्य करता है।

#include <vector>
#include <array>
#include <iostream>

template<typename T1, int SIZE>
void foo(std::vector<std::array<T1, SIZE>> bar) {
    std::cout << "SPECIFIC (array)" << std::endl;
}

int main() {
    std::vector<std::array<int, 3>> b(2, std::array<int, 3> {4, 5, 6});

    foo<int,3>(b);
}

कोड चलाएं


@Xaser क्योंकि ऐरे का दूसरा टेम्प्लेट तर्क प्रकार का है size_t...
जीन-बैप्टिस्ट यूंसे

2
R2RT की टिप्पणी को ध्यान में रखते हुए, संकलक विशिष्ट अंतर प्रतीत होते हैं।
Xaser

8

मुझे लगता है कि यह बस से एक लाइन के कारण है[temp.deduct.call]/4

सामान्य तौर पर, कटौती प्रक्रिया टेम्पलेट तर्क मानों को खोजने का प्रयास करती है जो कटौती किए गए ए को ए के समान बनाती है

स्पष्ट करने के लिए, Aपैरामीटर का मतलब है, से[temp.deduct.call]/1

... कॉल के संगत तर्क के प्रकार के साथ टेम्प्लेट तर्क कटौती (इसे कॉल करें A) ...

जैसा कि पहले ही बताया जा चुका है, आप जो समस्या देख रहे हैं उसे ठीक template<typename T1, int SIZE>करने के लिए बदल template<typename T1, size_t SIZE>रहे हैं। जैसा कि कहा गया है [temp.deduct.call]/4, संकलक कटौती करना चाह रहा है Aजो इसके समान है A। चूंकि std::arrayटेम्पलेट में तर्क हैं <class T, size_t N>(से [array.syn]), यह दूसरा पैरामीटर है, वास्तव में size_t, नहीं int

इसलिए, टेम्पलेट कटौती के लिए, के लिए अपने सामान्य समारोह template<typename T1>मिलान करने में सक्षम है बिल्कुल के प्रकार A, जहां-के रूप में अपने विशेष template<typename T1, int SIZE>एक नहीं है सटीक मैच। मेरा मानना ​​है कि MSVC अपनी कटौती में गलत है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.