2014-04-11 12 views
7

Sto cercando di capire std::is_convertible in C++ 11. Secondo cppreference.com, std::is_convertible<T,U>::value dovrebbe valutare su 1 iff "Se un valore immaginario di tipo T può essere utilizzato nell'istruzione di ritorno di una funzione che restituisce U". La formulazione non dice nulla su dove quella funzione potrebbe essere dichiarata, però. Cosa ci si dovrebbe aspettare quando il costruttore di copie di U è privato? Cosa ci si dovrebbe aspettare quando T è un riferimento lvalue?C++ 11 std: comportamento is_convertible con il costruttore di copie private

esempio considerare questo codice:

#include <iostream> 
#include <type_traits> 
struct Fact_A; 
struct A { 
    friend struct Fact_A; 
    A() = default; 
    A(A&&) = delete; 
private: 
    A(const A&) = default; 
}; 
struct Ref_A { 
    A* _ptr; 
    Ref_A(A* ptr) : _ptr(ptr) {} 
    operator A&() { return *_ptr; } 
}; 
struct Fact_A { 
    static A* make_A(const A& a) { return new A(a); } 
    static A f(A* a_ptr) { return Ref_A(a_ptr); } 
    //static A g(A&& a) { return std::move(a); } 
}; 
int main() { 
    A a1; 
    A* a2_ptr = Fact_A::make_A(a1); 
    (void)a2_ptr; 
    std::cout << std::is_convertible< Ref_A, A >::value << "\n" // => 0 
       << std::is_convertible< Ref_A, A& >::value << "\n" // => 1 
       << std::is_convertible< A&, A >::value << "\n"; // => 0 
} 

sto usando gcc-4.8.2 o clang-3.4 (nessuna differenza di uscita), e ho compilato con:

{g++|clang++} -std=c++11 -Wall -Wextra eg.cpp -o eg 

Qui, std::is_convertible< Ref_A, A > rapporti 0. Tuttavia, è possibile vedere che Fact_A::f restituisce un oggetto di tipo A e un rvalue di tipo Ref_A viene utilizzato nella dichiarazione di reso. Il problema è che il costruttore di copie di A è private, in modo che la funzione non possa essere posizionata altrove. Il comportamento attuale è corretto rispetto allo standard?

Seconda domanda. Se rimuovo private, l'output diventa 1 1 1. Cosa significa l'ultimo 1? Che cos'è un "rvalue di tipo A&"? È un riferimento di valore? Perché potresti notare che ho eliminato esplicitamente il costruttore di spostamenti di A. Di conseguenza, non posso dichiarare Fact_A::g. Ma ancora, std::is_convertible< A&, A > riporta 1.

risposta

6

is_convertible è definito come segue in [meta.rel]/4 da n3485:

data funzione il seguente prototipo:

template <class T> typename 
add_rvalue_reference<T>::type create(); 

la condizione del predicato per una specializzazione modello is_convertible<From, To> sarà soddisfatto se e solo se l'espressione di ritorno nel seguente codice sarà ben formata, comprese tutte le conversioni implicite nel tipo restituito di la funzione:

To test() { 
    return create<From>(); 
} 

e qui, avete bisogno di un/copiabile To mobile: Il ritorno-dichiarazione si applica una conversione implicita, e questo richiede un costruttore di copia/spostamento accessibili se To è un tipo di classe (T& non è una classe genere).

confronta con [conv]/3

Un'espressione e può essere convertito in modo implicito un tipo T se e solo se la dichiarazione T t=e; è ben formate, per alcuni inventato temporaneo variabile t.


Se From è T&, si ottiene qualcosa come

To test() { 
    return create<T&>(); 
} 

che, simile a std::declval, è un lvalue: L'espressione create<T&>() è/produce un lvalue, dal momento che T& && (via add_rvalue_reference) è compresso a T&.

+0

Grazie per il riferimento. Oltre a ciò che hai detto, c'è più testo direttamente sotto la bozza che hai citato, che menziona specificamente i problemi di contesto. Lo accetterò. Immagino che rimanga una domanda persistente sul fatto che lo standard stia facendo la cosa giusta. Quello che non mi piace è che 'is_convertible' sembra inutilmente legato all'accessibilità del costruttore di' To', che non ha nulla a che fare con 'From', o la relazione tra' From' e 'To'. Posso immaginare situazioni in cui voglio davvero sapere se la conversione può essere fatta in un contesto di mia scelta ... –

+1

@MateiDavid 'is_convertible' prova a simulare la definizione di * implicitamente convertibile *, che trovo un po 'non intuitivo. Questa definizione richiede di per sé un costruttore di copia/spostamento accessibile. Forse nel tuo contesto, 'is_constructible' ha più senso. – dyp

Problemi correlati