10

I was just playing around with the new std::function from C++11, and I wrote an example that compiles with clang++ 3.2 and the Intel C++ compiler 13.1 but not with g++ 4.8. Before I report this as a bug, I thought I'd check that I'm not doing something really stupid and that this should actually compile. So, is the following code valid c++11?

template <typename C>
void map(C& c, std::function<typename C::value_type(typename C::value_type)> f)
{
    for(auto& x : c) {
        x = f(x);
    }
}

int main()
{
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    map(v, [](int x) { return x+2; });

    for(auto x : v) {
        std::cout << x << std::endl;
    }
}

I realise that this code isn't very useful but it struck me as odd that clang and Intel C++ compiled it and gcc didn't.

EDIT: gcc will also not compile the same code when passing map a functor or function pointer:

struct {
    int operator() (int a) {
        return a+2;
    }
} add2s;
map(v, add2s);

int add2 (int a) {
    return a+2;
}
map(v,add2);

clang and icpc also compile both of these.

dtruby
  • 1,775
  • 2
  • 12
  • 9
  • What's the error, g++ shows you? – Kiril Kirov Apr 08 '13 at 10:59
  • clang 3.0 with -std=c++11 crash dumps on this code – nurettin Apr 08 '13 at 11:02
  • `'main()::' is not derived from 'std::function'` I guess, that's at least what I get. – filmor Apr 08 '13 at 11:03
  • @nurettin: Clang 3.0 is *old*. – Xeo Apr 08 '13 at 11:05
  • I would have expected such an error message for a reference or pointer parameter, but for a value it seems odd. – filmor Apr 08 '13 at 11:06
  • Just to note this (although you most certainly have tried this already) after manually converting the lambda to a `std::function` object the code works. – filmor Apr 08 '13 at 11:11
  • I get: `test.cpp:41:37: error: no matching function for call to ‘map(std::vector&, main()::__lambda0)’` – dtruby Apr 08 '13 at 11:14
  • Possible duplicate: http://stackoverflow.com/questions/9998402/c11-does-not-deduce-type-when-stdfunction-or-lambda-functions-are-involved – filmor Apr 08 '13 at 11:21
  • I wonder if it couldn't be related to the change @JonathanWakely is talking about [here](http://stackoverflow.com/a/15865276/1932150). Notice, that [you can fix this by adding braces aroung the lambda](http://liveworkspace.org/code/4yc7Hy$3809) – Andy Prowl Apr 08 '13 at 11:25
  • @filmor: There's no type deduction going on here, `C` is deduced from the first argument – Andy Prowl Apr 08 '13 at 11:26
  • Why not? `template void map(C& c, F f)` – balki Apr 08 '13 at 11:32
  • @balki: C should be deduced from the first argument, then replaced in the type of the second parameter. The second argument in itself does not participate to type deduction – Andy Prowl Apr 08 '13 at 11:35
  • @balki: (I'm referring to the OP's example in my previous comment, not yours. In your example of course there is type deduction going on for both parameter types) – Andy Prowl Apr 08 '13 at 11:37
  • @AndyProwl Ok. However, this seems to work in all compilers http://liveworkspace.org/code/6UvzJ$0 – balki Apr 08 '13 at 11:38
  • @balki: I don't doubt it: I believe the OP has hit a bug, and the bug is somehow related to copy-initialization of an `std::function` object. Your example does not use `std::function`. – Andy Prowl Apr 08 '13 at 11:47
  • @AndyProwl, it is related to that change I made to `std::function`, but only in as much as the change causes it to hit a G++ bug. The `std::function` change itself is OK and should compile, but doesn't, as shown by the reduced example in my answer below. – Jonathan Wakely Apr 08 '13 at 11:55
  • 1
    @AndyProwl, you're right there _shouldn't_ be any type deduction, because `function` is a non-deduced context, but for some reason that fails, but it works with `std::function` which should be equivalent. See the bugzilla report for more details. – Jonathan Wakely Apr 08 '13 at 12:04
  • 1
    @JonathanWakely: Thank you for clarifying once again. Your answer makes it clear that the change itself only helped revealing an existing bug, rather than being the culprit. (+1ed already) – Andy Prowl Apr 08 '13 at 12:05

1 Answers1

10

This is a G++ bug, it can be reduced to the following example which doesn't use std::function (or anything from the standard library):

template<typename T>
struct function
{
    function(int)
    { }
};

struct V {
  typedef int value_type;
};

template <typename C>
void map(C&, function<typename C::value_type>)
{
}

int main()
{
  V v;
  map(v, 1);
}

I've reported it to bugzilla as PR 56874. The problem is not related to lambdas, but to a type in a non-deduced context incorrectly causing argument deduction to fail.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • maybe add the part about non-deduced context from your comment to your answer, too. – Stephan Dollberg Apr 08 '13 at 12:29
  • Incidentally, you reported this as being specific to lambdas, but it will not compile when passing functors or function pointers either. Is that a different bug or part of the same one? – dtruby Apr 08 '13 at 12:55
  • @dtruby, I've updated the answer above and the bugzilla report: it won't compile when passing an `int` either – Jonathan Wakely Apr 08 '13 at 13:02