2015-11-26 17 views
15

Przykładowy czas z funkcji członka odniesienia kwalifikacjach wydaje się być coś takiego:const odniesienie funkcja wykwalifikowany członek

#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 
}; 

Działa to dobrze. Nie jest możliwe bezpośrednie pobranie bazowego wskaźnika PLIKu z nienazwanego tymczasowego. Jeśli jednak udostępnimy operatorowi odlewania, nie będzie to już działać.

Różne kompilatory po prostu połknąć bez skargi, mimo że jest to bardzo przydatne rozwiązanie. Weźmy na przykład funkcję członka std :: string :: c_str(). Czujesz, że powinien być kwalifikowany referencyjnie (ponieważ w przeciwnym razie masz nieprawidłowy wskaźnik), ale tak nie jest.

Czy to jest dziura w standardzie C++ 11? Czy coś mi umyka?

+4

Nie możesz sprawić, by kod był trochę bardziej gęsty? To więcej niż strona dla 2 metod. – user463035818

+2

Funkcja 'c_str()' jest użyteczna w parametrze, nawet jeśli jest tymczasowa. W 'f (g(). C_str());' ograniczone życie może być w porządku. –

+0

Na marginesie: nie wszystkie referencje wartości r są tymczasowe. – Hurkyl

Odpowiedz

16

Element tymczasowy może być powiązany z obiektem kwalifikowanym const&, a kwalifikator odwołania skutecznie kwalifikuje obiekt przekazany niejawnie (*this). Jeśli chcesz uniemożliwić wywoływanie plików tymczasowych, ale zezwalasz na wartości l, możesz = delete przeciążać odwołanie wartości rvalue i zaimplementować wersję l-wartości. Korzystanie const wykwalifikowanych kwalifikatorów odniesienia dla obu operatorów wymaga tylko jednego wdrożony i jedną realizację = delete d:

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

efekt netto jest to, że można korzystać z konwersji tylko dla obiektów, do której idziesz lwartością:

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

To wydaje się być rozwiązaniem. Nie sądzę, że konieczne jest dołączenie funkcji operatora, która nie jest stała. Nie wydaje mi się, że bez tego otrzymam niechciane zachowanie. –

+6

Zamiast '&& = delete' możesz użyć' const && = delete', w przeciwnym razie stała wartość będzie wiązała się z 'const &' overload –

+0

@PiotrSkotnicki: thanks - Nie wiedziałem o tej pętli. Odpowiednio zaktualizowałem odpowiedź. –

Powiązane problemy