Почему спецификаторы исключений в перегруженных операторах «<<» не работают ни с одним объектом std :: ostream, а с теми, которые определены в библиотеке? - PullRequest
1 голос
/ 24 марта 2019

exemplo.cpp:

#include <type_traits>
using std::is_same;

#include <utility>
using std::declval;

#include <iostream>
using std::ostream;
using std::cout;

struct Foo final {
    int value;
    inline constexpr Foo(const int i) noexcept : value{i} {};
    inline ~Foo() = default;
};

ostream& operator<<(ostream& out, const Foo& foo) noexcept { return out << foo.value; }

int main() {
    const Foo a(42);
    static_assert(is_same<decltype(cout), ostream>::value == true, ""); // assert always to true...

    static_assert(noexcept(cout << a) == true, ""); // assert to true if the operator on line 21 is defined noexcept(true)

    static_assert(noexcept(declval<ostream>() << a) == true, ""); // assert always to false...

    static_assert(noexcept(declval<decltype(cout)>() << a) == true, ""); // Same as line 32...

    return 0;
}

Команда компиляции:

g++ -std=c++2a -fconcepts exemplo.cpp -o exemp.run

Ошибка:

exemplo.cpp:32:53: error: static assertion failed
    static_assert( noexcept( declval<ostream>() << a) == true, ""); // assert always to false...
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
exemplo.cpp:34:60: error: static assertion failed
    static_assert( noexcept( declval<decltype(cout)>() << a) == true, ""); // same as line 32
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~

Функция 'declval ()' "генерирует объект времени псевдокомпиляции" данного типа, даже если этот тип на самом деле не является стягиваемым. Поэтому 'declval ()' должен создать другой объект, такой как std :: cout, в котором перегруженный оператор в строке 21 должен работать во время компиляции (но это не так).

Я понял, что это также работает с std :: clog и std :: cerr, обе переменные типа ostream.

Это должно просто скомпилироваться. Я имею в виду, что спецификатор исключения должен быть одинаковым для любого объекта ostream, не только для этих трех, очевидно.

Примечание: компиляция с G ++ 8.1.0; флаги на изображении не нужны. На самом деле, ни один флаг, или только флаг -std = c ++ 11 или выше, не может дать такой же вывод.

1 Ответ

0 голосов
/ 24 марта 2019

Причина в том, что declval генерирует временный объект, поэтому, если ваш код имеет другую перегрузку, такую ​​как

ostream& operator<<(ostream&& out, const Foo& foo) noexcept { return out << foo.value; }

, он будет работать.Обратите внимание, что перегруженная функция принимает ссылку на rvalue.Я проверил это с gcc 4.8.5 и -std=c++11.

...