2013-07-25 10 views
16

Sto cercando di andare d'accordo con std::function. Dal riferimento here si può vedere che l'argomento del codice std::function deve essere richiamabile e copiabile. Quindi ecco un piccolo esempio:std :: funzione per oggetto funzione MoveConstructible in gcc

#include <iostream> 
#include <type_traits> 
#include <functional> 

class A { 
public: 
    A(int a = 0): a_(a) {} 
    A(const A& rhs): a_(rhs.a_) {} 
    A(A&& rhs) = delete; 
    void operator()() 
    { 
     std::cout << a_ << std::endl; 
    } 

private: 
    int a_; 
}; 

typedef std::function<void()> Function; 

int main(int argc, char *argv[]) 
{ 
    std::cout << std::boolalpha; 
    std::cout << "Copy constructible: " 
       << std::is_copy_constructible<A>::value << std::endl; 
    std::cout << "Move constructible: " 
       << std::is_move_constructible<A>::value << std::endl; 
    //Function f = A(); 
    return 0; 
} 

Abbiamo chiamabile, copiabile ma non sposta classe costruibile. Credo che questo dovrebbe essere sufficiente per avvolgerlo in Function. Ma se commentate il commento del compilatore di commenti, il compilatore di riga diventa molto turbato dal costruttore di mosse eliminato. Ecco il link ideone. GCC 4.8.0 non compila anche questo.

Quindi, è qualcosa che non capisco circa std::function o è un comportamento errato di GCC?

+0

Ho appena provato con clang ++, lo stesso problema lì. –

+3

I _think_ la funzione 'delete'd è ancora considerata durante la risoluzione di sovraccarico, e in questo caso viene selezionata prima del costruttore di copie e causa l'errore. Per correggere, rimuovere la dichiarazione del costruttore di spostamento in quanto uno non verrà generato implicitamente a causa dell'esistenza del costruttore dichiarato dall'utente. Inoltre, vedi [questa domanda] (http://stackoverflow.com/questions/16897845/move-member-function-generation) per informazioni su "is_move_constructible". – hmjd

+1

@hmjd Yup. http://stackoverflow.com/q/14085620/1171191 – BoBTFish

risposta

11

GCC e Clang sono corretti.

§17.6.3.1.1 requisiti argomento di un template [utility.arg.requirements]

Tabella 20-requisiti MoveConstructible [moveconstructible].

  • T u = rv; è equivalente al valore di rv prima della costruzione.
  • T (rv); T (rv) è equivalente al valore di rv prima della costruzione.

Tabella 21 - requisiti CopyConstructible (oltre a MoveConstructible) [copyconstructible].

  • T u = v; il valore di v è invariato ed è equivalente a u.
  • T (v); il valore di v è invariato ed equivale a T (v).

Nota del:

requisiti CopyConstructible (oltre a MoveConstructible)

Vale a dire se qualcosa è CopyConstructible deve anche essere MoveConstructible. Anche se va bene implementare il movimento come una copia.

Aggiornamento:

Anche Trovo interessante il fatto che lo standard C++ 11 non sembra di definire is_copy_constructible in termini di CopyConstructible, vale a direessi non sono proprio la stessa cosa, is_copy_constructible è più rilassato in quanto richiede solo:

§20.9.4.3 proprietà Tipo [meta.unary.prop]

Tabella 49 - proprietà Type predicati

  • is_copy_constructible <T>; is_constructible < T, const T & > :: value is true.
4

Hai frainteso lo scopo della specifica di eliminazione. Un costruttore di mosse non è implementato di default. Se provi a spostare un oggetto senza un move-ctor, verrà semplicemente copiato. Se si specifica il costruttore di movimento come eliminato, proverà a chiamarlo e quindi a vederlo eliminato. Ciò significa: non è possibile copiare un oggetto temporaneo. Rimuovi l'istruzione move-constructor e funzionerà.

Edit - Chiarimento:

Se nessuna mossa costruttore viene dichiarata (dove = cancella è una dichiarazione), quindi una costruzione da un oggetto temporaneo chiamerà il costruttore di copia (da riferimento const). Se si dichiara un costruttore di mosse, una costruzione da un oggetto temporaneo proverà a chiamarla. Quindi, se dichiari che uno spostamento-ctor è stato eliminato, proverà a chiamare una funzione di cancellazione, che causerà un errore. Se non lo dichiari, ciò comporterà una chiamata del copy ctor.

Ecco perché il tuo esempio non funziona, se tu non lo avessi dichiarato, std :: function userebbe solo il copy-ctor.

Per impostazione predefinita intendevo: implementato se non dichiarato, come accade con il copy- o default-ctor.

Problemi correlati