2014-11-21 13 views
14

Recently I've discovered che a volte essere in grado di convertire i valori effettivi temporaneamente in lvalue può essere utile per me.È ben definito il cast di xvalues ​​su lvalue per passare alle funzioni?

Sto usando il seguente strumento:

#include <type_traits> 

template <typename T> 
inline constexpr std::remove_reference_t<T> &lvalue(T &&r) noexcept { 
    return static_cast<std::remove_reference_t<T> &>(r); 
} 

E 'utile quando si deve utilizzare le funzioni che richiedono lvalue come argomenti, ma non hanno alcun interesse per ciò che quei particolari valori ottengono cambiato in. Per quando sei interessato ad altri vettori di output che non sono correlati all'argomento specifico specificato.

Ad esempio, questo:

std::string get_my_file() { 
    std::ifstream ifs("myfile.txt"); 
    return {std::istreambuf_iterator<char>(ifs), {}}; 
} 

può essere modificato a questo:

std::string get_my_file() { 
    return {std::istreambuf_iterator<char>(lvalue(std::ifstream("myfile.txt"))), 
      {}}; 
} 

E questo:

std::string temp1 = get_my_shader(); 
const char *temp2 = temp1.c_str(); 
glShaderSource(a, 1, &temp2, nullptr); 

può essere modificato a questo:

glShaderSource(a, 1, &lvalue(get_my_shader().c_str()), nullptr); 

e consentire cose come questa:

void foo(int *x) { 
    std::cout << *x << std::endl; 
} 

foo(&lvalue(5)); 

Mi piacerebbe essere sicuro se sto invocando indefinito-comportamento o non in tutto questo, perché non vedo alcuna, anche se ci possono essere qualche regola di casting che lo renderebbe illegale (che ignoro). Per quanto riguarda la durata dei provvisori, non vedo alcun problema da quando, AFAIK, rvalues live until the end of full-expression e l'utilizzo della funzione è limitato a questo.

C'è una recente modifica alla norma sulla reinterpret_cast e xvalues che sembra essere il tema:

https://stackoverflow.com/a/26793404/1000282

EDIT:

versione migliore con riferimento collasso come suggerito:

template <typename T> 
constexpr T &lvalue(T &&r) noexcept { return r; } 
+0

Stai bene. L'unica cosa che puoi facilmente rovinare colando xvalues ​​su lvalues ​​è la durata, e hai ragione non c'è alcun pericolo nei tuoi esempi, dato che il temporaneo non è referenziato oltre la dichiarazione che lo crea. (La proposta 'reinterpret_cast' in realtà non tocca la tua domanda.) – Deduplicator

+0

@Deduplicator Grazie, ho dichiarato rvalues ​​invece di xvalue specifici, perché la domanda include anche espressioni come' & lvalue (5) '. Che tra l'altro sta funzionando bene. –

+1

BTW: Perché usi 'std :: remove_reference_t' invece delle regole di compressione di riferimento? – Deduplicator

risposta

9

Come hai detto, hai fatto attenzione a non lasciare che alcun puntatore o riferimento ai temporari sfuggisse al loro scopo.
L'utilizzo della funzione lvalue (il mio è chiamato no_move) rende più semplice interrompere involontariamente tale restrizione.

Successivamente, diamo un'occhiata a ciò che xvalues sono: oggetti in scadenza, ma tuttavia gli oggetti.
Ciò significa che è possibile ignorare che sono nel loro tour funebre (se li si passa a una funzione, tale funzione lo farà naturalmente, a meno che non si chieda di approfittarne).

L'ultimo punto che hai menzionato stava chiamando con un valore, che di certo non è un oggetto.
Ma anche questo non è un problema, come quando si chiama la funzione, verrà creato un temporaneo.
E quel temporaneo sopravvivrà naturalmente fino alla fine della dichiarazione.

Per inciso, utilizzando std::remove_reference_t<T>& è inutile per il ritorno tipo di lvalue, è possibile utilizzare direttamente T& e si basano sul riferimento-collasso-regole. Inoltre, lo static_cast e inline sono superflui.

template <typename T> constexpr T& lvalue(T&& r) noexcept {return r;} 
Problemi correlati