2015-11-26 25 views
15

Lo stock esempio di una funzione membro di riferimento qualificato sembra essere qualcosa di simile:const riferimento funzione di membro qualificato

#include <stdio.h> 
#include <stdexcept> 
#include <string> 

// Easy access to literals 
using namespace std::literals; 

// File wrapper 
class File { 
    private: 
    // The wrapped file 
    FILE *_file; 
    public: 
    File(const char *name) : 
     _file(fopen(name, "r")) { 
     // unable to open the file? 
     if (!_file) throw std::runtime_error{ "Unable to open file: "s + name }; 
    } 
    ~File() { 
     fclose(_file); 
    } 

    // Convert to the underlying wrapped file 
    operator FILE *() & { 
     return _file; 
    } 

    // TODO: Member functions for working with the file 
}; 

Questo metodo funziona bene. Non è possibile recuperare direttamente il puntatore FILE sottostante da un temporaneo senza nome. Tuttavia, se rendiamo anche l'operatore di casting const-qualificato, questo sembra non funzionare più.

Diversi compilatori semplicemente lo inghiottono senza lamentarsi anche se è un'idea terribilmente utile. Prendi, ad esempio, la funzione membro std :: string :: c_str(). Si ritiene che dovrebbe essere qualificato come riferimento (perché altrimenti si dispone di un puntatore non valido) eppure non lo è.

Si tratta di un buco nello standard C++ 11? Mi sto perdendo qualcosa qui?

+4

non riesci a rendere il codice un po 'più denso? È più di una pagina per 2 metodi – user463035818

+2

Il 'c_str()' è utile in un parametro, anche se è temporaneo. In 'f (g(). C_str());' la durata limitata può essere ok. –

+0

A parte: non tutti i riferimenti di valore r sono temporanei. – Hurkyl

risposta

16

Un oggetto temporaneo può essere associato a un oggetto qualificato const& e il qualificatore di qualifica effettivamente qualifica l'oggetto implicitamente passato (*this). Se si desidera impedire chiamate su provvisori ma consentire lvalue, è possibile = delete il sovraccarico di riferimento rvalore e implementare la versione lvalue. Utilizzando const qualificazioni di riferimento qualificato sia per gli operatori richiede un solo attuata e un'implementazione = delete d:

class File { 
    // ... 
    FILE* _file; 
public: 
    operator FILE*() const&& = delete; 
    operator FILE*() const& { return this->_file; } 
    // ... 
}; 

L'effetto netto è che si può utilizzare la conversione solo per gli oggetti a cui si va un lvalue:

int main() { 
    File  f; 
    File const cf{}; 

    FILE* fp = f;    // OK 
    FILE* cfp = cf;   // OK 
    FILE* tfp = File();  // ERROR: conversion is deleted 
    FILE* mfp = std::move(cf); // ERROR: conversion is deleted 
} 
+0

Questa sembra essere la soluzione. Non penso sia necessario includere la funzione dell'operatore non const. Non sembro ottenere alcun comportamento indesiderato senza di esso. –

+6

Invece di '&& = delete' potresti usare' const && = delete', altrimenti un constvalore si legherebbe a un 'const &' overload –

+0

@PiotrSkotnicki: grazie - Non ero a conoscenza di questo loop-hole. Ho aggiornato la risposta in modo corrispondente. –

Problemi correlati