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;
}
Compile command:
g++ -std=c++2a -fconcepts exemplo.cpp -o exemp.run
Errors:
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
The 'declval()' function "generates a pseudo compile time object" of a given type, even if this type isn't really contructible. So 'declval()' should produce another object like std::cout, in which the overloaded operator in line 21 should work at compile time (but it doesn't).
I realised that is also works to std::clog and std::cerr, both variable of ostream type.
It should just compile. I mean the exception especifier should be the same to any ostream object, not only for these three obviously.
Note: compiling with G++ 8.1.0; the flags on the image are not needed. Actually, no flag or only the flag -std=c++11 or greater may give the same output.
The reason is that declval
generate a temp object, so if you code has another overload, like this
ostream& operator<<(ostream&& out, const Foo& foo) noexcept { return out << foo.value; }
it will work. Note that the overloaded function takes rvalue reference. I tested it with gcc 4.8.5 and -std=c++11
.