2013-03-15 5 views
14

Quando CRTP viene utilizzato all'interno di un modello, (o in genere quando un parametro modello viene passato come argomento del modello di classe base), è impossibile denominare i modelli membro della base in una dichiarazione using?Utilizzo della dichiarazione per il nome del modello dipendente dal tipo

template< typename d > 
struct base { 
    template<typename> 
    struct ct {}; 

    template<typename> 
    void ft() {} 
}; 

template< typename x > 
struct derived : base< derived<x> > { 
    using derived::base::template ct; // doesn't work 
    using derived::base::ft; // works but can't be used in a template-id 
}; 

Mi sembra che questo sia un buco nella lingua, semplicemente perché il utilizzando-dichiarazione di produzione grammatica non incorpora un qualificata id.

using-declaration: 
    using typename(opt) nested-name-specifier unqualified-id ; // have this 
    using :: unqualified-id ; 

unqualified-id: 
    identifier 
    operator-function-id 
    conversion-function-id 
    literal-operator-id 
    ~ class-name 
    ~ decltype-specifier 
    template-id 

qualified-id: 
    nested-name-specifier template(opt) unqualified-id // want this 
    :: identifier 
    :: operator-function-id 
    :: literal-operator-id 
    :: template-id 

Se l'unica regola erano using-declaration: using typename(opt) qualified-id, le uniche conseguenze sarebbero

  • escludere :: conversion-function-id, :: ~ class-name, e :: ~ decltype-specifier template-id che non hanno alcun senso semantico,
  • permettendo :: template-id che è già espressamente vietato dalla 7.3.3/5 e
  • che consente la parola chiave template che ha già specifiche sufficienti per correggere il buco.

Questa analisi è corretta?

Dato che la nuova grammatica era consentita, forse una dichiarazione con typename dovrebbe importare un modello di classe o un modello di alias e uno senza typename dovrebbe importare una funzione o un modello di variabile nell'ambito corrente.

 using typename derived::base::template ct; 
    using derived::base::ft; 

Ciò potrebbe richiedere alcune specifiche aggiuntive. Inoltre, lo status quo attuale sembra essere che i nomi dei modelli dipendenti abbiano sempre un tipo ambiguo (non id template), quindi non è chiaro che typename appartiene a ct.

+0

Un'analisi interessante. Sono curioso di sapere dove useresti * questo in modo tale che il "buco" identificato sarebbe inibitore. Cioè cos'è un'applicazione del mondo reale in cui questo è il posto di blocco che ti costringe a fare un passo indietro e a riconsiderare l'architettura del programma? – WhozCraig

+0

@WhozCraig Arriva ogni volta che usi CRTP da un modello. La classe base fornisce un'interfaccia per la quale devi dire 'questo -> * template' o' base :: template' ad ogni utilizzo. – Potatoswatter

+0

Ok, penso di averlo capito. Questo caso particolare riguarda l'utilizzo di quella con una clausola 'using' per semplificare la vita, ma non sembra consentita. Buon esempio. Grazie. – WhozCraig

risposta

2

I seguenti funziona bene con C++ 11:

#include <iostream> 

template< typename d > 
struct base { 
    template<typename> 
    struct ct {}; 

    template<typename> 
    void ft() {std::cerr << "cheesecake" << std::endl;} 
}; 

template< typename x > 
struct derived : base< derived<x> > { 
    template<typename X> 
    using ct = typename derived::base::template ct<X>; // new in C++11 
    using derived::base::ft; 
}; 

int main() 
{ 
    derived<int>::ct<float> c; 
    derived<int> a; 
    a.ft<int>(); 
} 

Se questo non è quello che volevi, ti invitiamo a dare un esempio di come si vorrebbe utilizzare ct e ft?

+1

Sì, l'alias del modello funziona, sebbene richieda la ripubblicazione della firma del modello che interrompe in qualche modo la separazione delle preoccupazioni. La funzione 'using' declaration non funziona nell'ambito di' derived'. L'inoltro perfetto funzionerebbe. Ma questi non stanno usando le dichiarazioni. Il gioco di piedi aggiunto sconfigge lo scopo di una dichiarazione 'using', che consiste nell'importare una dichiarazione da un ambito a uno correlato * senza * che dichiara qualcosa di nuovo. Ad ogni modo ... aggiungi l'inoltro perfetto e dovrei accettarlo. – Potatoswatter