为什么重载运算符上的异常说明符'<<'不适用于任何 std::ostream 对象,但对库中定义的运算符不起作用?

Why exception specifiers on overloaded operators '<<' doesn't work to any std::ostream object, but does on those defined in the library?

本文关键字:lt 运算符 不起作用 定义 对象 适用于 异常 重载 说明符 不适用 std      更新时间:2023-10-16

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 或更高版本可以给出相同的输出。

原因是

declval生成一个临时对象,所以如果你的代码有另一个重载,像这样

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

它会起作用。请注意,重载函数采用右值引用。我用 gcc 4.8.5 和 -std=c++11 对其进行了测试。

您不能将 prvalue ostream绑定到ostream &,而是应该有一个 ostream & 表达式。

int main() {
    const Foo a(42);
    static_assert(is_same<decltype(cout), ostream>::value == true, ""); 
    static_assert(noexcept(cout << a) == true, "");
    static_assert(noexcept(declval<ostream&>() << a) == true, "");
    static_assert(noexcept(declval<decltype(cout)&>() << a) == true, ""); 
    return 0;
}

现场观看