Domanda

Quale parte del C ++ specifica limita argomento di ricerca dipendente dal trovare modelli di funzione nel set di spazi dei nomi associati? In altre parole, perché l'ultima chiamata in seguito main non riescono a compilare?

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.
}
È stato utile?

Soluzione

Questa parte spiega:

C ++ standard 03 14.8.1.6 :

[Nota: Per i nomi delle funzioni semplici, argomento di ricerca dipendente (3.4.2) si applica anche quando il nome della funzione non è visibile nell'ambito di applicazione della chiamata. Ciò è perché la chiamata ha ancora la forma sintattica di una chiamata di funzione (3.4.1). Ma quando si utilizza un modello di funzione con argomenti espliciti template, la chiamata non ha la forma sintattica corretta a meno che non v'è un modello di funzione con quel nome visibile nel punto della chiamata. In assenza di tale nome è visibile, la chiamata non è sintatticamente ben formato e di ricerca argomento-dipendente non si applica. Se un nome del genere è visibile, argomento di ricerca dipendente si applica e modelli di funzionalità aggiuntive possono essere trovati in altri spazi dei nomi.

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
}

Altri suggerimenti

Vorrei raffinare risposta un po 'accettato. Non è chiaro nella questione OP, ma la parte importante dallo standard (citato da Kornel) è questo (sottolineatura mia):

Ma quando un modello di funzione con argomenti template espliciti è usato, la chiamata non ha la forma sintattica corretta

Allora, qual è proibito è fare affidamento su ADL e con argomenti espliciti template. Purtroppo usando non argomenti di tipo template richiede l'utilizzo di argomenti espliciti (a meno che abbiano valori di default).

Di seguito è riportato il codice di esempio che mostra questo:.

[Live]

#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);
}

Poiché c ++ 20, adl funziona anche bene con il modello funzione esplicita. Ecco la proposta: P0846R0: Modelli ADL e di funzione che non sono visibili :

Invece di richiedere all'utente di utilizzare la parola chiave modello, una revisione delle regole di ricerca è stato proposto in modo che un nome per il quale una ricerca normale produce né alcun risultato o trova una o più funzioni e che è seguito da AA "<" sarebbe trattato come se un nome di modello di funzione era stato trovato e causerebbe ADL per essere eseguita.

Al momento, solo GCC 9 ha implementare questa funzione, così il vostro esempio può compilare.

live demo .

Edit: No, questo non è giusto. Vedere @ di Kornel risposta .


Non sono del tutto sicuro, ma dopo aver consultato Stroustrup "The C ++ linguaggio di programmazione" Penso che la sezione Appendice C 13.8.4 potrebbero essere la causa.

Dato frob è un modello di uno, concettualmente, potrebbe specializzarsi per i=0 in un punto dopo lo chiamate. Ciò significa che l'attuazione sarebbero lasciati con due possibili modi di scegliere quali frob alla chiamata come appare si può scegliere nel punto di istanziazione o , alla fine del trattamento l'unità di traduzione.

Quindi, penso che il problema è che si possa fare

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*/ }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top