4

Recently I have come across the question discussed is_streamable type trait. So I decided to implement my own version and come up with the next solution to check if the type can be read from std::istream or not:

template<typename, typename = void>
struct is_readable_from_stream_impl
    : std::false_type {};

template<typename T>
struct is_readable_from_stream_impl<T, 
    std::void_t<decltype(std::declval<std::istream&>() >> std::declval<T>())>>
    : std::true_type {};

template<typename T>
struct is_readable_from_stream :
    is_readable_from_stream_impl<T> {};

template<typename T>
inline constexpr auto is_readable_from_stream_v = is_readable_from_stream<T>::value;

So far, so good. I added then a custom structure with overloaded operator>>:

struct readable {};

std::istream& operator>>(std::istream& is, readable&)
{
    return is;
}

and tested the type trait:

static_assert(is_readable_from_stream_v<readable&>);
static_assert(!is_readable_from_stream_v<readable>);

The checks were passed with both gcc 8.2 and clang 6.0.0, but MSVC rejects the second assert.

I am wondering if I my implementation (or test) is incorrect or it is another issue with MSVC.

Edgar Rokjān
  • 17,245
  • 4
  • 40
  • 67
  • Shouldn't the name of this trait be something like "is readable from stream using >> operator"? There are lots of other ways of reading from a stream. –  Sep 04 '18 at 19:09
  • @NeilButterworth it is a toy example, I didn't actually care about naming that much... – Edgar Rokjān Sep 04 '18 at 19:10

1 Answers1

6

The problem here is that MSVS can bind rvalues to lvalue-references as a language extension. The following code compiles:

struct readable{ };

void foo(readable&)
{ }

void bar()
{
    foo(readable{});
}

Use can use /Za option (Disable Language Extensions) to disable it. Then your asserts will be passed.

Evg
  • 25,259
  • 5
  • 41
  • 83
  • Ah, I guess it is a second or third time I forget about this wonderful extension. That is a good point! – Edgar Rokjān Sep 04 '18 at 19:21
  • 3
    I'd recommend using `/permissive-` if you can, rather than just `/Za`. It makes MSVC conform to the standard in many places that it doesn't normally do so. – Justin Sep 04 '18 at 19:32
  • Just to confirm - MSVS enables rvalues to lvalue-references *and* rvales to const-lvalue-references (which is standard)? – Fureeish Sep 04 '18 at 19:52
  • 2
    @Fureeish, yes, rvalues to lvalue-refs per an extension, rvalues to const-lvalue-refs per the Standard. – Evg Sep 04 '18 at 20:02