2013-05-27 11 views
12

Il Clang documentation spiega perfettamente cheÈ anche un costruttore predefinito ereditato definito dall'utente?

Se una classe o struct ha alcun costruttore predefinito definito dall'utente, C++ non permetterà di default costruire un esempio const a come questo ([dcl.init] , p9)

il seguente codice ha una tale costruttore di default definita dall'utente per Base, ma g ++ e Clang non sono d'accordo se il costruttore predefinito per Derived è definito dall'utente, anche se Derived fa ereditano esplicitamente tutte le Base costruttori (utilizzando il new C++11 inheriting constructors feature)

#include <iostream> 

class Base 
{ 
public: 
    Base(): b_(0) {} // look! user-defined default constructor 
    void print() const { std::cout << b_ << "\n"; } 
private: 
    int b_; 
}; 

class Derived 
: 
    public Base 
{ 
    using Base::Base; // does this constitute a user-defined default constructor? 
}; 

int main() 
{ 
    Base const b; 
    b.print(); // 0 for g++ & CLang 

    Derived const d; 
    d.print(); // 0 for g++, Clang: "default initialization of an object of const type 'const Derived' requires a user-provided default constructor" 
} 

g ++ 4.8 accetta volentieri questo codice, ma Clang 3.3 non lo fa. Cosa dice lo standard?

NOTA: senza un costruttore di default definita dall'utente per Base, né g ++ 4.8 né Clang 3,3 accettare Base const b; (mentre ad esempio g ++ 4.7.2 precedentemente accettato che). Dato che g ++ conosce la regola, penso che ciò implichi che g ++ consideri il costruttore predefinito per Derived come definito dall'utente. Ma Clang 3.3 pensa diversamente.

UPDATE: in base alla risposta @JesseGood s' che 0/1 costruttori argomenti non sono mai ereditati, ho provato a cambiare il costruttore Base a

Base(int b = 0, void* = nullptr): b_(b) {} 

ma non risolvere il problema Clang.

+0

hai ragione, stavo fraintendendo la domanda. –

risposta

7

Clang è corretto.

Il passo rilevante sulle istanze const è da 8.5p7:

Se un programma richiede l'inizializzazione predefinita di un oggetto di un tipo const qualificati T, T deve essere un tipo di classe con un costruttore predefinito fornito dall'utente.

Da Base(): b_(0) {} è fornito dall'utente, Base const b; va bene.

La parte successiva è importante 12.9p3:

Per ogni costruttore non-template nel set candidato del ereditati costruttori diversi da un costruttore non avere parametri o un costruttore copiare/spostare avere un parametro singolo, un costruttore è dichiarato implicitamente con le stesse caratteristiche del costruttore a meno che non esista un costruttore dichiarato dall'utente con la stessa firma nella classe in cui viene visualizzata la dichiarazione di utilizzo

La parte importante qui è il testo in grassetto.Credo che questo escluda il tuo caso dal momento che Base() è un costruttore che non ha parametri. Ciò significa che lo Derived non ha un costruttore predefinito fornito dall'utente (sebbene uno sia ancora implicitamente dichiarato).

Ciò significa anche che i costruttori predefiniti, di copia e spostamento da una classe base sono mai ereditati.

+0

+1 grazie per la risposta. Se cambio la firma del costruttore 'Base' in' Base (int b = 0, void * = nullptr): b_ (b) {} ', il costruttore predefinito viene soppresso. Ma Clang dà ancora l'errore su "Derived" (e g ++ lo accetta). Un costruttore con 2 parametri predefiniti conta anche come costruttore non ereditato senza parametri? – TemplateRex

+2

@rhalbersma: Sì, conta ancora come un ctor non ereditario senza parametri. 'Base (int)' e 'Base (int, void *)' sono ereditati però. (ma, gli argomenti predefiniti non sono ereditati). –

+0

Grazie, ho accettato la tua risposta. – TemplateRex

Problemi correlati