2

It seems like this should be legal:

decltype(declval<istream>().operator>>(declval<istream>(), declval<int>())) test;

But when I try to compile I get:

error C2661: std::basic_istream<char,std::char_traits<char>>::operator >>: no overloaded function takes 2 arguments

Am I doing something wrong? Why doesn't this evaluate to an istream?

EDIT:

It has been pointed out that because istream& istream::operator>>(int&) is a method, the first value is passed automatically.

However: decltype(declval<istream>().operator>>(declval<int>())) test; errors with:

error C2664: std::basic_istream<char,std::char_traits<char>> &std::basic_istream<char,std::char_traits<char>>::operator >>(std::basic_streambuf<char,std::char_traits<char>> *): cannot convert argument 1 from std::ios_base::iostate to std::basic_istream<char,std::char_traits<char>> &(__cdecl *)(std::basic_istream<char,std::char_traits<char>> &)

And decltype(istream::operator >> (declval<istream>(), declval<int>())) test; errors with:

error C2661: std::basic_istream<char,std::char_traits<char>>::operator >>: no overloaded function takes 2 arguments

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • A member `oparator<<` of `istream` will not take `istream` as a first parameter. – StoryTeller - Unslander Monica Jan 17 '17 at 12:53
  • @StoryTeller You're saying that will be passed implicitly then right? – Jonathan Mee Jan 17 '17 at 12:54
  • @JonathanMee - as is always the case with member functions. – StoryTeller - Unslander Monica Jan 17 '17 at 12:55
  • 1
    Why not simply use `decltype(std::declval() >> std::declval())`? This should work even for non-member overloads of `operator >>`... – W.F. Jan 17 '17 at 12:57
  • 1
    `istream& istream::operator<<(const int&)` is not a thing, for obvious reasons. – Barry Jan 17 '17 at 13:04
  • @Barry I miss-typed. I think I cleaned it up correctly? Or are you seeing one that I'm missing? – Jonathan Mee Jan 17 '17 at 13:08
  • @JonathanMee About edit: `operator>>` is **not** static. It cannot be called directly on class `istream` (unless you want to take address of it or want to use it in one or two other cases) – W.F. Jan 17 '17 at 13:09
  • @Barry Oops. Comment remvoed – NathanOliver Jan 17 '17 at 13:09
  • Why not just use `istream&` instead of all the nouveau metatypoclassology? – n. m. could be an AI Jan 17 '17 at 13:15
  • @n.m. Yeah, I'm actually trying to use this in an `enable_if` to ensure that the extraction operator exists. – Jonathan Mee Jan 17 '17 at 13:20
  • @Barry Ugh, I've edited again. – Jonathan Mee Jan 17 '17 at 13:21
  • @W.F. Honestly I tried, but failed at the syntax, somehow or other, I'm making all kinds of dumb mistakes today. – Jonathan Mee Jan 17 '17 at 13:25
  • @JonathanMee I know that in production code one shouldn't but for the type debug purpose I find it easier to use `typeid(decltype(STH)).name()` + `c++filt -t RESULT`. This of course don't help you with references but should, but as long you remember this it can be really helpful – W.F. Jan 17 '17 at 13:30
  • @W.F. It seems like what you're offering here is simply over my head. What is `STH` and is `c++filt -t RESULT` some kind of crazy code syntax I've never heard of? – Jonathan Mee Jan 17 '17 at 13:37
  • 1
    @JonathanMee I meant something like [this](http://coliru.stacked-crooked.com/a/a380fbe84d8d2eb8). Of course this can't solve every possible problem but when you're not sure about the type of something it clearly does the trick. – W.F. Jan 17 '17 at 13:55
  • @W.F. I getcha. I was actually looking to use this in an `enable_if` though. So while this is helpful as a surefire check of function availability, I need the meta-programming support, provided by your and the answer's suggestion. – Jonathan Mee Jan 17 '17 at 14:03
  • 1
    @JonathanMee sure you want :) but you could inspect the types in a run-time to apply the knowledge in compile-time :) – W.F. Jan 17 '17 at 14:06

1 Answers1

7

The operator>> that takes an int is a member function (you're currently using the syntax for both member and nonmember functions) and it takes its argument by reference (so that it can populate it - declval<int>() gives you an int&&, you need declval<int&>() to get an int&):

using T = decltype(declval<istream>().operator>>(declval<int&>()));

Even better would be to not invoke the operator directly, so you don't have to worry about which operator<< is a member and which is not:

using T = decltype(declval<istream&>() >> declval<int&>());
Barry
  • 286,269
  • 29
  • 621
  • 977