Подтвердить что ты не робот

Почему замена многомерных массивов не исключена?

У меня есть следующий фрагмент:

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

Используя GCC 4.9.0, это печатает 0. Я не понимаю, почему.

В соответствии со стандартом существуют две перегрузки для 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)));
}

В моем понимании спецификатор noexcept для массива должен работать рекурсивно для многомерных массивов.

Почему заменяются многомерные массивы не noexcept?


При попытке найти минимальный пример, который по-прежнему ведет себя странно, я пришел к следующему:

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

Используя GCC 4.9.0, это печатает 1 1 0, но опять же я не понимаю, почему.

4b9b3361

Ответ 1

Эта перегрузка:

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

не находится в области действия до ;, поэтому swap(*a, *b) не учитывает эту перегрузку. Это происходит из-за:

3.3.2/1 Точка объявления для имени сразу же после его полного объявления (раздел 8) и перед его инициализатором (если есть)...

и спецификация исключения является частью декларатора.