-5

Is it possible to call a function which takes an rvalue reference to a function? For example:

#include <iostream>    

void foo(void(&f)(int))
{
    std::cout << "A" << std::endl;
}

void foo(void(&&f)(int))
{
     std::cout << "B" << std::endl;
}

Can I call the overload of foo that prints "B"?

Barry
  • 286,269
  • 29
  • 621
  • 977
rubix_addict
  • 1,811
  • 13
  • 27
  • 2
    _"So here: blahblahblah"_ Uhmm what please? Did you ask a question actually?? You want _to win_ what exactly? Elaborate please, [edit] your quesiton. Is that a mantled _Gimme teh codez plz_ request? – πάντα ῥεῖ Jun 29 '15 at 22:23
  • What did you try? And why don´t you try a bit harder to write the required text? (Btw, a r-value reference for a function pointer?) – deviantfan Jun 29 '15 at 22:23
  • 1
    `void f(int); struct wrap{using T=void(&&)(int); operator T(){return f;}}; foo(wrap{})` Works in [gcc](http://coliru.stacked-crooked.com/a/016901ea880113ba), fails in [clang](http://coliru.stacked-crooked.com/a/83a204add167012a). – David G Jun 29 '15 at 22:25
  • @0x499602D2 that's interesting... I wonder why it compiles in gcc and does not in clang. – rubix_addict Jun 29 '15 at 22:45
  • 1
    @rubix_addict I think gcc *and* clang are wrong here. In gcc the lvalue overload should be called since the result of the operator function should be an lvalue even if it's return type is an rvalue reference. And clang isn't even trying to call `wrap`'s operator function (which it should). – David G Jun 29 '15 at 23:30
  • Wasn't this question adequately [answered by @0x499602D2](http://stackoverflow.com/a/31125846/2069064) the last time you asked it? – Barry Jun 29 '15 at 23:31
  • Note that in clang, doing [`static_cast(wrap{})`](http://melpon.org/wandbox/permlink/2VcBe0PF5Y8UvVTd) does the conversion and correctly calls the lvalue overload. – David G Jun 29 '15 at 23:34

1 Answers1

2

This is not possible.

When you have two candidate functions like these, the overload taking an lvalue reference to function type is always preferred over the rvalue reference overload. Functions are considered lvalues in all cases so the conversion to an lvalue reference is the strongest. Here is some standard wording ([over.ics.rank]/p3.2.4):

Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if

  • S1 and S2 are reference bindings (8.5.3) and S1 binds an lvalue reference to a function lvalue and S2 binds an rvalue reference to a function lvalue. [ Example:

    int f(void(&)()); // #1
    int f(void(&&)()); // #2
    void g();
    int i1 = f(g); // calls #1
    

— end example]


The code from my comment presented here calls overload #2 in gcc and is rejected by clang.

void foo(void(&)(int)); // #1
void foo(void(&&)(int)); // #2

void f(int);
struct wrap {
    using T = void(&&)(int);
    operator T() { return f; }
};

int main() {
    foo(wrap{}); // Calls #2 in gcc, error in clang
}

The Clang error is:

non-const lvalue reference to type void (int) cannot bind to a temporary of type wrap

GCC is obviously wrong because of the above quote, but Clang is also wrong as well. The result of the operator function is an lvalue so it should bind to the lvalue overload, but it seems that clang is not attempting the conversion. A simpler example is:

void (&r)(int) = wrap{}; // OK in gcc, error in clang

So this looks like a bug in Clang and GCC.

David G
  • 94,763
  • 41
  • 167
  • 253
  • 1
    I don't think you are reading the reference-compatibility rules correctly. `wrap{}.operator T()` is an lvalue of function type `void (int)`, used to initialize a lvalue reference to `void (int)`. – T.C. Jun 30 '15 at 06:10
  • MSVC (both 2013 and 2015 pre-release) compiles your example and correctly selects the lvalue reference overload. IntelliSense in 2013 doesn't agree, but the one in 2015 accepts the code as well. – bogdan Jun 30 '15 at 08:24
  • Is this a bug in GCC? Would it be OK to report it? – rubix_addict Jun 30 '15 at 08:58
  • @T.C. I figure the value category of the operator function call is an lvalue expression but its *type* is still an rvalue-reference. Since its type (rvalue reference) is not reference-compatible with the parameter (lvalue reference) the implicit conversion fails. Is this not a correct interpretation? – David G Jun 30 '15 at 13:28
  • No, expressions don't really have reference type. See [expr]/p5. – T.C. Jun 30 '15 at 13:29
  • @T.C. I see. In that case then clang is wrong. – David G Jun 30 '15 at 13:34
  • @rubix_addict Yes, see the edit. It is a bug in clang and gcc for the reasons explained in my answer and [in my comment](http://stackoverflow.com/questions/31126559/overloading-on-valueness-rvalue-lvalue-of-a-function-type/31128008#comment50266712_31126559). They can be reported [here](http://llvm.org/bugs/) and [here](https://gcc.gnu.org/bugzilla/) respectively. – David G Jun 30 '15 at 15:00