3

I've puzzled over this meta-function for a long time. It seems to work, but I suspect it to contain UB, when it checks for size of a possibly undefined reference type? Is there a problem with this meta-function?

template <class S, class C, typename = void>
struct is_streamable : ::std::false_type { };

template <class S, class C>
struct is_streamable<S,
  C,
  decltype(void(sizeof(decltype(::std::declval<S&>() <<
    ::std::declval<C const&>()))))
> : ::std::true_type
{
};

EDIT: The motivation for my question (and worries) was this question. Why did he not use a similar trick (checking size of a reference type)?

Community
  • 1
  • 1
user1095108
  • 14,119
  • 9
  • 58
  • 116
  • 1
    your trait fails if `operator<<` of streamable object returns `void`. why are you checking decltype of sizeof of expression, casted to void, instead of using just the voidified decltype of expression? – Piotr Skotnicki Nov 11 '14 at 21:02
  • @PiotrS. Good idea! I think I did it precisely because the streaming instances (ostream const&) should not return void. – user1095108 Nov 11 '14 at 21:12
  • http://codereview.stackexchange.com/ – user2485710 Nov 11 '14 at 21:18

1 Answers1

2

when it checks for size of a possibly undefined reference type?

That never induces UB. It would just result in a deduction failure (according to [temp.deduct]/8), causing the primary template to be instantiated. [expr.sizeof]:

When applied to a reference or a reference type, the result is the size of the referenced type.

The sizeof operator shall not be applied to an expression that has […] incomplete type […].

But a yet incomplete ostream is regarded "streamable" for a string if the global operator<< is overloaded.
To fix that, define the partial specialization as

template <class S, class C>
struct is_streamable<S, C,
    decltype(void( std::declval<S&>() << std::declval<C const&>() ))
    > : ::std::true_type
{};

Demo.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • And I haven't commited any other non-portable offense or UB? – user1095108 Nov 11 '14 at 20:57
  • @user1095108 I only know saw what the problem with your code is. It should work for an incomplete `ostream` with defined `operator<<`. Changed my answer appropriately, check the demo. – Columbo Nov 11 '14 at 21:14