ADL फ़ंक्शन टेम्प्लेट क्यों नहीं खोजता है?


85

C ++ विनिर्देशन का कौन-सा भाग संबद्ध नामस्थानों के सेट में फ़ंक्शन टेम्प्लेट खोजने से तर्क निर्भर देखने को प्रतिबंधित करता है? दूसरे शब्दों में, mainनीचे दिया गया अंतिम कॉल संकलन में विफल क्यों होता है ?

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
    void non_template(foo const&) {}
}

int main() {
    ns::foo f;
    non_template(f); // This is fine.
    frob<0>(f); // This is not.
}

क्या इसका मतलब है, कि आपको ns :: frob () लिखे बिना frob () काम करने की उम्मीद है?
साइमन

हां, एक गैर-टेम्पलेट फ़ंक्शन के तरीके से।
ह्यूग

FYI करें उपरोक्त कोड कोमू में भी विफल रहता है: comeaucomputing.com/tryitout - संकलन using namespace ns;में ns::योग्यता उत्तीर्ण या जोड़ना । यह अच्छा प्रश्न है।
fbrereto

3
@ हव्वा: बस इसके द्वारा काटे गए :) मजेदार कैसे स्पष्ट योग्यता नियम ADL बाहर मुझे लगता है: /
Matthieu M.

1
@ मैट: हाहा, और मुझे भी अभी। छोटी प्रोग्रामिंग की दुनिया।
GManNickG

जवाबों:


88

यह हिस्सा इसे समझाता है:

सी ++ मानक 03 14.8.1.6 :

[नोट: सरल फ़ंक्शन नामों के लिए, तर्क आश्रित लुकअप (3.4.2) तब भी लागू होता है जब फ़ंक्शन नाम कॉल के दायरे में दिखाई नहीं देता है। ऐसा इसलिए है क्योंकि कॉल में अभी भी फ़ंक्शन कॉल (3.4.1) का सिंटैक्टिक रूप है। लेकिन जब स्पष्ट टेम्पलेट तर्क के साथ एक फ़ंक्शन टेम्पलेट का उपयोग किया जाता है, तो कॉल में सही सिनेटिक रूप नहीं होता है जब तक कि कॉल के बिंदु पर दिखाई देने वाले उस नाम के साथ एक फ़ंक्शन टेम्पलेट नहीं होता है। यदि ऐसा कोई नाम दिखाई नहीं दे रहा है, तो कॉल सिंटैक्टली रूप से अच्छी तरह से गठित नहीं है और तर्क-निर्भर लुकअप लागू नहीं होता है। यदि ऐसा कुछ नाम दिखाई दे रहा है, तो तर्क निर्भर लुकअप लागू होता है और अन्य नामस्थानों में अतिरिक्त फ़ंक्शन टेम्पलेट मिल सकते हैं।

namespace A {
  struct B { };
  template<int X> void f(B);
}
namespace C {
  template<class T> void f(T t);
}
void g(A::B b) {
  f<3>(b);    //ill-formed: not a function call
  A::f<3>(b); //well-formed
  C::f<3>(b); //ill-formed; argument dependent lookup
              // applies only to unqualified names
  using C::f;
  f<3>(b);    //well-formed because C::f is visible; then
              // A::f is found by argument dependent lookup
}

9
इसके लिए तर्क क्या है? एक अजीब आवश्यकता की तरह लगता है। मेरा मतलब है, वाक्य रचना का किसी भी चीज़ से क्या लेना-देना है?
ऑर्बिट

22
Vandevoorde और Josuttis में @LightnessRacesinOrbit धारा 9.3.5 बताता है कि क्यों यह है एक वाक्यात्मक समस्या (ओ पी के उदाहरण के लिए अपनाया नाम देना): "एक संकलक कि तय नहीं कर सकता f<3>(b)एक समारोह कॉल तर्क जब तक यह निर्णय लिया है कि है <3>एक टेम्पलेट तर्क सूची है इसके विपरीत, हम। यह तय नहीं कर सकता कि <3>यह एक टेम्पलेट तर्क सूची है, जब तक कि हमें f()एक टेम्पलेट नहीं मिला है। क्योंकि इस चिकन और अंडे की समस्या का समाधान नहीं किया जा सकता है, अभिव्यक्ति के रूप में पार्स किया जाता है (f<3)>(b), जिसका कोई मतलब नहीं है। " ध्यान दें कि यह templateसदस्य फ़ंक्शन टेम्प्लेट के लिए वितरण सिंटैक्स के समान है ।
टेम्प्लेक्स

9
क्या इस मुद्दे को ठीक करने का कोई प्रस्ताव है? template f<3>(b)एक बेहतर वाक्यविन्यास हो सकता है?
बाल्की

1
@AngelusMortis अभिव्यक्ति के ( भाव ... ) (कोष्ठक से पहले ऑपरेटर की कमी पर ध्यान दें) हमेशा एक फ़ंक्शन कॉल है, हालांकि, और कंपाइलर जानता है कि जैसे ही वह खुले कोष्ठक को देखता है। यहां समस्या यह है कि <दोनों एक ऑपरेटर के रूप में और एक टेम्पलेट तर्क सूची की शुरुआत के रूप में सेवा कर सकते हैं, और संकलक को यह पता लगाने के लिए बहुत अधिक अतिरिक्त पार्स करना होगा कि (और संभवतः कोड की कुछ व्यवस्थाएं हैं जहां यह संभव नहीं है करने के लिए) यह मानक लेखकों को लगता है कि अवैध बनाने के लिए चुने गए हैं, शायद संकलक डेवलपर्स के बालों को बचाने के लिए।
मिरल

3
इस आवश्यकता को C ++ 20 में हटा दिया गया है और OP का कोड अब अच्छी तरह से बन गया है :)
Rakete1111

8

C ++ 20 के बाद से, adl भी स्पष्ट फ़ंक्शन टेम्पलेट के साथ ठीक काम करता है। यहाँ प्रस्ताव है: P0846R0: ADL और फ़ंक्शन टेम्प्लेट जो दृश्यमान नहीं हैं :

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

वर्तमान में, केवल जीसीसी 9 ने इस सुविधा को लागू किया है, इसलिए आपका उदाहरण संकलन कर सकता है।

live demo


5

मैं थोड़ा स्वीकार किए गए उत्तर को परिष्कृत करना चाहूंगा। ओपी प्रश्न में यह स्पष्ट नहीं है, लेकिन मानक (कोर्नेल द्वारा उद्धृत) से महत्वपूर्ण हिस्सा यह है (जोर मेरा):

लेकिन जब स्पष्ट टेम्प्लेट तर्कों के साथ फ़ंक्शन टेम्पलेट का उपयोग किया जाता है, तो कॉल में सही वाक्यविन्यास फ़ॉर्म नहीं होता है

इसलिए जो निषिद्ध है वह ADL पर निर्भर है और स्पष्ट टेम्पलेट तर्क का उपयोग कर रहा है। दुर्भाग्य से गैर-प्रकार के टेम्पलेट तर्कों का उपयोग करने के लिए स्पष्ट तर्कों का उपयोग करने की आवश्यकता होती है (जब तक कि उनके पास डिफ़ॉल्ट मान न हों)।

नीचे नमूना कोड दिखाया गया है।

[लाइव]

#include <string>
#include <utility>

namespace C {
  struct B { };
  template<class T> void f(T t){}
}

void g(C::B b) {
  f(b);           // OK
  //f<C::B>(b);   // ill-formed: not a function call, but only 
                  //  because explicit template argument were used

  std::string s;
  move(s);                      // OK
  //move<std::string&>(s);      // Error, again because 
                                //  explicit template argument were used
  std::move<std::string&>(s);   // Ok
}

int main()
{
 C::B b;
 g(b);
}

0

संपादित करें: नहीं, यह सही नहीं है। देखें @ कोर्नेल के जवाब


मुझे पूरी तरह यकीन नहीं है लेकिन स्ट्रॉस्ट्रुप की "द सी ++ प्रोग्रामिंग लैंग्वेज" से परामर्श करने के बाद मुझे लगता है कि अपेंडिक्स सी सेक्शन 13.8.4 का कारण हो सकता है।

चूँकि frobएक टेम्प्लेट है जिसे i=0आप इसे कॉल करने के बाद एक बिंदु पर विशेष रूप से उपयोग कर सकते हैं । इसका मतलब यह है कि कार्यान्वयन को चुनने के दो संभावित तरीकों के साथ छोड़ दिया जाएगा, frobजैसा कि यह प्रतीत होता है कि यह इसे तात्कालिकता के बिंदु पर या अनुवाद इकाई के प्रसंस्करण के अंत में चुन सकता है ।

इसलिए, मुझे लगता है कि समस्या यह है कि आप क्या कर सकते हैं

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
}

int main() {
    ns::foo f;
    frob<0>(f);
    return 0;
}

namespace ns {
    template<> void frob< 0 >(foo const&) { /* Do something different*/ }
}

1
नहीं, नामस्थान के ले और आप अभी भी अपनी समस्या है, है ना? उपयोग के बाद विशेषज्ञता C ++ में एक सामान्य समस्या है, विशेष रूप का उपयोग नहीं किया जाता है यदि बाद में घोषित किया जाता है।
कोर्नेल किलीविलेज़

@ कोर्नेल: आह हाँ, यह एक अलग त्रुटि देता है, जो मैंने वर्णित किया है उसके अनुरूप एक और। काफी उचित है, यह इंगित करने के लिए धन्यवाद।
Troubadour
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.