2014-11-07 17 views
20

Mam następujący fragment:Dlaczego nie można wymieniać tablic wielowymiarowych?

#include <algorithm> 
#include <iostream> 

int main(int argc, char** argv) { 
    int x[2][3]; 
    int y[2][3]; 

    using std::swap; 
    std::cout << noexcept(swap(x, y)) << "\n"; 

    return 0; 
} 

Korzystanie GCC 4.9.0, to drukuje 0. Nie rozumiem, dlaczego.

Zgodnie z normą tam dwa przeciążenia dla std::swap:

namespace std { 
    template<class T> void swap(T& a, T& b) noexcept(
     is_nothrow_move_constructible<T>::value && 
     is_nothrow_move_assignable<T>::value 
    ); 

    template<class T, size_t N> 
    void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b))); 
} 

W moim wyrozumienia noexcept specifier na tablicy powinna działać rekursywnie dla wielowymiarowych tablic.

Dlaczego wymienia się tablice wielowymiarowe na noexcept?


Starając się znaleźć minimalny przykład, który nadal zachowuje się dziwnie wymyśliłem następujące:

#include <iostream> 

template<class T> struct Specialized  : std::false_type {}; 
template<>  struct Specialized<int> : std::true_type {}; 

template<class T>    void f(T& a) noexcept(Specialized<T>::value); 
template<class T, std::size_t N> void f(T (&a)[N]) noexcept(noexcept(f(*a))); 

int main(int argc, char** argv) { 
    int x, y[1], z[1][1]; 

    std::cout << noexcept(f(x)) << " " 
       << noexcept(f(y)) << " " 
       << noexcept(f(z)) << "\n"; 
} 

używając GCC 4.9.0 Drukuje 1 1 0, ale znowu nie rozumiem dlaczego.

+1

[clang say 1] (http://coliru.stacked-crooked.com/a/9d1c1e7307dda039) –

+0

Wydaje mi się bardzo dziwny. Znalazłem [DR 809] (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#809), który [pojawia się] (https://gc.gnu.org/ onlinedocs/gcc-4.9.0/libstdC++/api/a01316_source.html # l00185) należy zaimplementować (https://gc.gnu.org/onlinedocs/libstdc++/manual/bugs.html) w libstdC++, więc może błąd leży gdzie indziej. Zgodnie z ostatnią zmianą, [klang] (http://coliru.stacked-crooked.com/a/79dd288d30d8f159) wypisuje również '1 1 0'. clang z libC++ wyświetla "0" dla oryginalnego fragmentu. –

+0

[Coliru] (http://coliru.stacked-crooked.com/a/7fa0b200e56d1bd4), [2] (http://coliru.stacked-crooked.com/a/485e10b802dd3a96) –

Odpowiedz

11

To przeciążenie:

template<class T, size_t N> 
void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b))); 

nie jest w zakresie aż ;, więc swap(*a, *b) nie uważa tego przeciążenia. Wynika to z:

3.3.2/1 Punktem deklaracji o podanie nazwy jest natychmiast po jej całkowitym declarator (klauzula 8), a przed jego inicjator (jeśli w ogóle) ...

i specyfikacja wyjątków jest częścią deklaratora.

+3

Wydaje się to dość poważnym niedopatrzymaniem w standardzie. W obecnej formie nie działają naiwne rekurencyjne deklaracje 'noexcept'. Co gorsza, sam standard używa tych naiwnych deklaracji rekurencyjnych. – orlp

+5

Powiedz Świętemu Mikołajowi; położy Bjarne'a na niegrzecznej liście. – rightfold

+0

Jest to znana wada. Zobacz [LWG2456] (http://wg21.cmeerw.net/lwg/issue2456). – FrankHB

Powiązane problemy