Domanda

Ho un problema per quanto riguarda i puntatori membri. Il seguente codice non riesce a compilare utilizzando CC ed entrambi Oracle Solaris Studio 12.2 di Cygwin GCC 4.3.4, ma funziona con Microsoft Visual C ++ 2010:

struct A {
  int x;
};

struct B : public A {
};

template<typename T> class Bar {
public:
  template<typename M> void foo(M T::*p);
};

int main(int, char *[]) {
    Bar<B> bbar;
    bbar.foo(&B::x);
    return 0;
}

Al successivo all'ultima riga entrambi i compilatori di cui sopra non riescono a trovare una corrispondenza per Bar<B>::foo(int A::*). Ho scritto un semplice test per confermare che il tipo di &B::x espressione è in realtà int A::*:

// ...

static void foo(int A::*p) {
  std::cout << "A" << std::endl;
}

static void foo(int B::*p) {
  std::cout << "B" << std::endl;
}

int main(int, char *[]) {
    foo(&B::x);  // prints "A", even on MS VC++ 2010 
    return 0;
}

Il seguente soluzione funziona con GCC (non testato con ancora un Oracle CC), ma non riesce con VC ++ a causa di ambiguità:

template<typename T> class Bar {
public:
  template<typename M> void foo(M T::*p);
  template<typename M, typename _T_base> inline void foo(M _T_base::*p) {
      foo(static_cast<M T::*>(p));
  }
};

La mia domanda: Quale comportamento è corretto? A quanto pare VC ++ fa un upcast implicita da int A::* a int B::* per soddisfare la chiamata al modello funzione di membro, non dovrebbero gli altri due compilatori in considerazione di fare lo stesso?

È stato utile?

Soluzione

Una conversione da int A::* a int B::* è consentito, e non è questo il problema. Il problema è in detrazione modello di argomentazione, come si può vedere se si tenta il seguente programma che fornisce un <int> modello argomento per B::foo e compila, e una funzione foo2 non membro, che produce lo stesso errore di B::foo fatto prima.

struct A {
  int x;
};

struct B : public A {
};

template <typename T> class Bar {
public:
  template<typename M> void foo(M T::*p);
};

template<typename M> void foo2(M B::*p);

int main(int, char*[]) {
  Bar<B> bbar;
  bbar.foo<int>(&B::x);
  foo2(&B::x); // error, but foo2<int>(&B::x) would work.
  return 0;
}

Credo che questa situazione non è coperto dai casi in cui si suppone il compilatore di dedurre l'argomento <int> modello da solo. 14.8.2.1p3:

  

In generale, i tentativi di processo deduzione per trovare valori degli argomenti di template che renderanno la dedotta Un identico ad A (dopo il tipo A si trasforma come descritto sopra). Tuttavia, ci sono tre casi che permettono una differenza:

  • Se la P originale è un tipo di riferimento, il dedotta A (cioè, il tipo indicato dal riferimento) può essere più cv-qualificati di A.
  • A può essere un altro puntatore o puntatore al tipo di utente che può essere convertito alla dedotta A attraverso una conversione di qualificazione (conv.qual).
  • Se P è una classe, e P ha la forma modello-id, allora A può essere una classe derivata della A. dedotta Allo stesso modo, se P è un puntatore ad una classe di forma modello-id, A può essere un puntatore a una classe derivata a cui punta il dedotta a.

Ecco "P" è della funzione template tipo di argomento: M B::*p, dove il parametro tipo di modello M è da determinare. "A" è il tipo di argomento reale: int A::*. P e A non sono certo un riferimento o una classe, e il tipo di conversione di puntatore-a-membro avremmo bisogno per questo di lavoro non è una conversione di qualificazione (che descrive solo const / manipolazioni volatili come X* a const X* o int X::* a const int X::* ).

Quindi, l'argomento modello non può essere dedotto, e si dovrebbe aggiungere il parametro modello esplicito <int> al codice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top