为什么重载运算符 '<<' 上的异常说明符对任何 std::ostream 对象不起作用,但对库中定义的对象起作用?
Why exception specifiers on overloaded operators '<<' doesn't work to any std::ostream object, but does on those defined in the library?
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()' 函数 "generates a pseudo compile time object",即使这种类型实际上不是可构造的。所以 '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
.
测试了它
您不能将纯右值 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;
}
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()' 函数 "generates a pseudo compile time object",即使这种类型实际上不是可构造的。所以 '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
.
您不能将纯右值 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;
}