2016-06-20 7 views
8

Ho notato che l'implementazione di libstdC++ di std::ignore accetta un argomento const T&, che non può essere associato a un valore volatile. Da qui il seguente codice non riesce a compilare:È errato libstdC++ rifiutare l'assegnazione di valore volatile a std :: ignore?

#include <tuple> 
#include <utility> 
struct C {}; 
using VC = C volatile; 
int main() { 
    std::tuple<VC> t; 
    std::tie(std::ignore) = std::move(t); 
} 

(http://coliru.stacked-crooked.com/a/7bfc499c1748e59e)

È questo in violazione della norma, o c'è una clausola che rende questo comportamento indefinito?

+0

Perché si vuole utilizzare 'volatile' in primo luogo? Disabilita le ottimizzazioni, non rende le cose thread-safe. Non vedo perché lo farebbe ... –

+1

@JesperJuhl * perché è lì * – Brian

+0

Non è un buon motivo. Il codice può essere cambiato. –

risposta

0

Non sono un avvocato linguistico, quindi risponderò a questa domanda il più direttamente possibile.

ignore si trova nella sinossi tuple in tuple.general come tale:

// [tuple.creation], tuple creation functions: 
const unspecified ignore; 

Come avrete notato, l'attuazione libstdc++ definisce ignore come questo:

// A class (and instance) which can be used in 'tie' when an element 
    // of a tuple is not required 
    struct _Swallow_assign 
    { 
    template<class _Tp> 
     const _Swallow_assign& 
     operator=(const _Tp&) const 
     { return *this; } 
    }; 

considerando che la versione libc++ lo definisce come this:

template <class _Up> 
struct __ignore_t 
{ 
    template <class _Tp> 
     _LIBCPP_INLINE_VISIBILITY 
     const __ignore_t& operator=(_Tp&&) const {return *this;} 
}; 

Come tale, compila in libC++. Ora la definizione di std::tie può essere trovato in [tuple.creation] che dice:

Returns: tuple<Types&...>(t...). Quando un argomento in t è ignore, l'assegnazione di qualsiasi valore all'elemento di tupla corrispondente ha nessun effetto.

Questo non dice nulla circa ignore sé, quindi ho intenzione di gesso questo fino a non specificato comportamento. È possibile affermare che il comportamento indefinito è non omogeneo, ma potrebbe essere un allungamento.

+1

Non sono sicuro di aver capito.Questo non specifica il comportamento abbastanza bene in modo che il codice che ho postato debba avere * nessun effetto *, che non sembra dare la licenza di implementazione per rifiutare il codice? – Brian

+0

@Brian * Nessun effetto * è di per sé sottodeterminato. 'std :: tie' non ha clausole * effects *. L'operatore = 'in' ignore' non fa altro che 'return * this', quindi è un no-op, che si adatta perfettamente sotto una definizione di * no effects *. In entrambi i casi, il codice viene rifiutato a causa di come viene implementata la libreria, non a causa di una violazione di una qualsiasi delle clausole sotto 'std :: tie'. –

+0

No, non dice che la funzione 'std :: tie' non ha effetti; dice che "l'assegnazione di qualsiasi valore all'elemento tuple corrispondente non ha alcun effetto". – Brian

0

Commento:

// g++ 4.8.4 
int main() { 
    volatile int vi; 
    std::ignore = vi; 

    // error: no match for ‘operator=’ (
    //  operand types are ‘const std::_Swallow_assign’ 
    //  and ‘std::remove_reference<volatile int&>::type {aka volatile int}’ 
    //) 
    // std::ignore = std::move(vi); 

    // However this compiles: 
    volatile int&& vir = std::move(vi); 
    std::ignore = vir; 
} 
+0

Hmm interessante ... –