3

I have created a method with the following signature in a C++ header:

template<class _Ty>
class x {
public:

    // ...

    template<class func_Ty>
    x *where(func_Ty &);
}

My code expects func_Ty to be callable (i.e. function pointer, lambda, or class that overloads operator()), takes a single parameter of type _Ty or _Ty &, and returns a bool or bool &. I call the function with this code (s is x<int> *):

s->where([](int i){ return i % 2 == 0;});

This compiles fine on MSVC, but GCC gives me an error:

no matching function for call to ‘x<int>::where(main()::__lambda0)’

If i add a * in front of the lambda, GCC compiles fine, but MSVC gives me an error:

error C2100: illegal indirection

Is this a bug in one of the compilers? Or maybe both of these solutions are non-standard? Either way, is there some way to make the same code work on both compilers?

Nick Mertin
  • 1,149
  • 12
  • 27
  • Why not use `std::remove_if`? – erip Apr 25 '16 at 13:28
  • 4
    Totally unrelated to your problem, but you should not name any of your symbols with a leading underscore followed by an upper-case letter, as those kind of symbols [are reserved for the "implementation"](http://stackoverflow.com/a/228797/440558) (compiler and standard library). – Some programmer dude Apr 25 '16 at 13:30
  • 1
    Names that begin with an underscore followed by a capital letter (`_Ty`) and names that contain two consecutive underscores are reserved to the implementation. Don't use them. – Pete Becker Apr 25 '16 at 13:30
  • @erip I see now that that will work instead of my `where` function, however that does not solve the lambda syntax issue, which is transferable to other scenarios. – Nick Mertin Apr 25 '16 at 13:31
  • @JoachimPileborg thank you, I did not know that – Nick Mertin Apr 25 '16 at 13:31
  • @MagikM18 In general, avoid copying styles from headers in the std library; the std library is free to use reserved symbol names (that is sort of what they are for), while you are not. Sadly, enough std library style copying happens that people copy off people who copy off it without knowing why. :) – Yakk - Adam Nevraumont Apr 25 '16 at 13:37
  • @Yakk yes, I believe that's what happened to me. – Nick Mertin Apr 25 '16 at 13:43

1 Answers1

10

As far as I know it's a VS extension that allows non-const references to bind to temporaries. The standard disallows this.

The lambda is a temporary and the parameter of where is a non-const reference.

So change:

x *where(func_Ty &);

to

x *where(const func_Ty &);

or

x *where(func_Ty);

This

template<class func_Ty>
x *where(func_Ty&&);

would work too as in this case it's a forwarding reference.

bolov
  • 72,283
  • 15
  • 145
  • 224
  • you may also want to answer the second part of the question – Piotr Skotnicki Apr 25 '16 at 13:33
  • 1
    Thank you, this worked perfectly. I can't believe I missed that detail. Will accept as soon as it lets me – Nick Mertin Apr 25 '16 at 13:35
  • @MagikM18 Or `func_Ty&&`, which in this context is a forwarding reference that will bind to both lvalues and rvalues (temporaries or not). – Yakk - Adam Nevraumont Apr 25 '16 at 13:36
  • @bolov for a non-capturing lambda, perhaps this first triggers a conversion to a function pointer, which is then dereferenced, not sure though – Piotr Skotnicki Apr 25 '16 at 13:38
  • @Yakk I just tried that, doesn't work on either compiler – Nick Mertin Apr 25 '16 at 13:41
  • 1
    @bolov: if a lambda has as type "pointer to function..." then a dereference would transform it to "function ...", which would decay to "pointer to function..." immediately. Unless there is some detail where C++ differs from C in this situation. The funny effect is that you can call a function via a function pointer in many ways, such as `(*fptr)(1)`, `fptr(1)`, or `(********fptr)(1)`. – Olaf Seibert Apr 25 '16 at 14:35
  • But, since it appears that the type of a lambda isn't a function pointer but some `std::function<...>`, the point I was trying to make is moot. – Olaf Seibert Apr 25 '16 at 15:08