14

When I compile the following code with MSVC++, I get an error:

struct A
{
    template<typename T>
    void operator<<(T&& x)
    {
    }

};
void f()
{
}
int main()
{
    A().operator<<( f );  // ok
    A() << f;             // error

    return 0;
}

g++ and clang both compile this code fine. AFAIK, 'ok' and 'error' lines do exactly the same thing, and type T is deduced to void(&)(). Or is it void() and rvalue references to function are allowed? If so, what is their meaning? Is it ok to pass functions by reference like that? Is it MSVC++ bug that it fails to compile 'error' line? BTW, the error output:

no operator found which takes a right-hand operand of type 'overloaded-function' (or there is no acceptable conversion)
could be 'void A::operator <<<void(void)>(T (__cdecl &&))'
with[ T=void (void) ]
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
dsi
  • 586
  • 3
  • 13
  • 1
    can you provide the version of your c++ compiler? – xis Feb 05 '13 at 20:31
  • MSVC++2012 with NOV CTP update, gcc 4.5.3 and 4.7.2 tested, clang 3.0 and 3.1 tested. – dsi Feb 05 '13 at 20:36
  • I don't have VC11, so it's hard for me to investigate, but it smells like a bug with URef collapsing. The compiler mistakenly interprets it as an RRef to function and does not accept an lvalue in input. It would be interesting to check whether `typedef void (* test)(); test g() { return f; } ... A() << g();` would work – Andy Prowl Feb 05 '13 at 20:47
  • function pointers do work, I checked that already, using &f instead of f when doing << call – dsi Feb 05 '13 at 20:54
  • @dsi: That's not related to `&f` being a function pointer IMO: I think it works because `&f` is an rvalue. If you passed an lvalue, it would not work. Like `test* t = &f; A() << t;`. Is this the case? – Andy Prowl Feb 05 '13 at 20:59
  • @AndyProwl All of the following do work: `typedef void (*testp)(); typedef void (&testr)(); testr gr() { return f; } testp gp() { return f; } A() << gr(); A() << gp(); testr tr = f; testr tp = f; A() << tr; A() << tp;` – dsi Feb 05 '13 at 21:16
  • @dsi: OK, I give up investigating then. Anyway it looks like a bug report would be deserved. – Andy Prowl Feb 05 '13 at 21:18
  • 5
    OK, I filed a [bug report](http://connect.microsoft.com/VisualStudio/feedback/details/778613) – dsi Feb 05 '13 at 23:05
  • Yes, `T` should be deduced (in both statements) as `void (&)()`. – aschepler Feb 13 '13 at 03:53

2 Answers2

4

Why void operator<<(T&& x)? void operator<<(T& x) serves the purpose.

Function can be called with x() inside overloaded function as below

struct A
{
    template<typename T>
    void operator<<(T& x)
    {
        x();
    }

};
void f()
{
}

int main()
{
    A().operator<<( f );
    A() << f;             
    return 0;
}
Akshay
  • 94
  • 5
  • 1
    No, I use rvalue reference so that temporary _function objects_ would be moved, not copied. For _functions_ either way will work the same though. – dsi Feb 21 '13 at 17:25
3

So, answering my own question:

The code provided is valid and while rvalue references to functions are allowed (they act identical to lvalue references), here during template deduction T should become void(&)().

A bug in MSVC prevents my code from compiling.

UPDATE: The bug has been fixed in Visual Studio 2013 compiler

dsi
  • 586
  • 3
  • 13