2016-06-20 16 views
8

Zauważyłem, że implementacja libstdC++ z std::ignore przyjmuje argument const T&, który nie może wiązać się z niestabilnym rwartem. Stąd poniższy kod nie kompilacji:Czy libstdC++ jest błędne, aby odrzucić przypisanie zmiennej rvalue do 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)

Czy to z naruszeniem normy, czy też istnieje klauzula, która czyni tę niezdefiniowanej zachowanie?

+0

Dlaczego chcesz użyć 'volatile' w pierwszej kolejności? Wyłącza optymalizacje, nie sprawia, że ​​wątki są bezpieczne. Nie rozumiem, dlaczego to zrobiłeś ... –

+1

@JesperJuhl * ponieważ jest tam * – Brian

+0

Nie bez powodu. Kod można zmienić. –

Odpowiedz

0

Nie jestem prawnikiem językowym, więc odpowiem na to pytanie tak bezpośrednio, jak to możliwe.

ignore znajduje się w streszczeniu tuple w tuple.general jako takie:

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

Jak zauważył, wdrożenie libstdc++ definiuje ignore tak:

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

Podczas gdy wersja libc++ definiuje ją jak to:

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

Jako taki, kompiluje się w libC++. Teraz definicja std::tie można znaleźć w [tuple.creation], który mówi:

Powroty: tuple<Types&...>(t...). Gdy argument w t jest ignore, przypisanie dowolnej wartości do odpowiedniego elementu krotki ma brak efektu.

ten nie mówi nic o samej ignore, więc mam zamiar kreda to do nieokreślonym zachowanie. Można argumentować, że jest to zachowanie nieokreślone przez zachowanie, ale może to być rozciąganie.

+1

Nie jestem pewien, czy rozumiem.Czy to nie określa zachowania na tyle dobrze, że napisany przeze mnie kod powinien mieć * brak efektu *, który wydaje się nie dawać licencji implementacyjnej na odrzucenie kodu? – Brian

+0

@ Brian * Brak efektu * jest sam w sobie określony. 'std :: tie' nie ma klauzuli * effects *. 'Operator =' w 'ignore' nie robi niczego poza' return * this', więc jest no-op, który idealnie pasuje do jednej definicji * bez efektów *. Tak czy inaczej, kod jest odrzucany z powodu sposobu implementacji biblioteki, a nie z powodu naruszenia którejkolwiek z klauzul w ramach 'std :: tie'. –

+0

Nie, nie oznacza to, że funkcja 'std :: tie' nie ma żadnych efektów; mówi, że "przypisanie dowolnej wartości do odpowiedniego elementu krotki nie ma żadnego efektu". – Brian

0

Komentarz:

// 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 interesujące ... –