5

Lets say I have a class with a member variable:

std::unordered_map<KeyType, std::shared_ptr<ValueType>> myMap

and in a member function I want to do the following:

std::for_each(myMap.begin(), myMap.end(), [](std::pair<const KeyType, std::shared_ptr<ValueType>>& pair){pair.second->someMethod(); });

Is there anyway to shorten the lambda expression? I thought I could do this but it was not valid syntax:

std::for_each(myMap.begin(), myMap.end(), [](decltype(myMap::valueType)& pair){pair.second->someMethod(); });
grivescorbett
  • 1,605
  • 1
  • 21
  • 29
  • `using namespace std;` would shorten it a bit. – user703016 Apr 28 '12 at 17:53
  • 3
    @Soohjun good god, don't do that :( – 111111 Apr 28 '12 at 18:08
  • 1
    @111111: It’s fine in a small local scope in a definition, just not globally or in a header. – Jon Purdy Apr 28 '12 at 18:10
  • 2
    @JonPurdy I know it can be used in some cases but it is A LOT easier to just not use it. I would far rather see `using std::unodered_map` or whatever than including the entire namespace. And I really don't think recommending at as a comment in this question is at all constructive. – 111111 Apr 28 '12 at 18:13
  • @111111: I disagree. It’s more constructive to say “do it when it’s appropriate” than “don’t do it”. Whether it’s more *helpful* is another jar of jam. – Jon Purdy Apr 28 '12 at 18:21
  • @JonPurdy I really don't think, things are in namespace for a reason, and that isn't to have the namespace effectively merged with the current NS. The fact is it is never wrong to prefix a namespace, however it is Often (but not always) wrong to include an namespace, so it is a much better catch all advice to just recommend that you prefix. Especially by the medium of Stackoverflow comments where your hardly going to be able to teach some when and when not to prefix. – 111111 Apr 28 '12 at 18:44
  • @111111: Fair enough. It’s fine to err on the side of caution. – Jon Purdy Apr 28 '12 at 18:57
  • You're trying to `decltype` a type rather than a expression -- you already have a type (though it's misspelled). ;-] – ildjarn Apr 28 '12 at 19:41

3 Answers3

9

I wouldn’t bother with a lambda at all. Unlike the other standard algorithms, for_each() is not any more expressive or readable than the equivalent for.

for (auto& p : myMap)
    p.second->someMethod();

for (auto p = myMap.begin(); p != myMap.end(); ++p)
    p->second->someMethod();
Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
  • 1
    Actually, I would even say that `for_each` is as well as deprecated with the new range-for syntax. You had some benefits before (at the cost of writing a predicate), but now ? It's no even worth it. – Matthieu M. Apr 28 '12 at 19:23
  • @Klaim: Good point. Then again, there is always an ordinary `for`. If it weren’t for the typing issues, `for_each()` might save some keystrokes, but as it is, `for` still comes out on top in many cases. – Jon Purdy Apr 29 '12 at 05:00
  • Interesting, this all came about after I read this article today: http://evincarofautumn.blogspot.com/2012/04/c-functional-style-tips.html but perhaps in this case using a simple ranged for loop is the best answer? – grivescorbett Apr 29 '12 at 07:09
  • @JonPurdy Actually, I was commenting MatthieuM. remark that I find wrong as there are interesting differences between range-based-for and for_each that make them both useful, including the classic for as you wrote it. They are not eclipsing each other. – Klaim Apr 29 '12 at 15:42
  • @grivescorbett: I wrote that article. `for` is sometimes better. :P – Jon Purdy Apr 30 '12 at 13:07
5

I recomend typedefing complex templates like the assoc containers, for this reason so you could do something like:

typedef std::unordered_map<KeyType, std::shared_ptr<ValueType>> map_type;

map_type myMap;

//do with map

std::for_each(myMap.begin(), myMap.end(), 
    [](typename map_type::value_type& pair){
        pair.second->someMethod(); 
});

or without the typedef

std::for_each(myMap.begin(), myMap.end(), 
    [](typename decltype(myMap)::value_type& pair){
        pair.second->someMethod(); 
});

decltype gets the type of an object, you need to use the typename defined in a templated class, to do this you use the typename keyword. This is necessary in case a template specialisation doesn't have that typedef.

111111
  • 15,686
  • 6
  • 47
  • 62
0

I've made a macro which goes as this: // Anonymous lambda type deduction from container name

#define _A(container)\
  std::remove_reference<decltype(*std::begin(container))>::type

In your case use as:

std::for_each(myMap.begin(), myMap.end(), [](_A(myMap)& pair) {
  pair.second->someMethod(); 
});

Note: The remove_reference is needed to preserve constness if typing [](const _A(myMap)& pair), otherwise the & removes the const declaration.

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
  • No it's not, and you can use it for every algorithm, not just for_each. – Viktor Sehr Apr 28 '12 at 19:26
  • I don't mean the macro itself (though, well, I use `typedef` usually so it would not be as useful with my coding style), I mean the `for_each` you wrote. `for (auto& p: myMap) { p.second->someMethod(); }` is **much** shorter. – Matthieu M. Apr 28 '12 at 19:48
  • Yes, in the case of foreach, but I took it a bit like a general question regarding all algorithms (and the code gets alot more readible if you use different algorithms instead of for\forloops for everything). And nowadays, with auto, you don't need to typedef everything. – Viktor Sehr Apr 28 '12 at 20:16
  • I still like to `typedef` because `std::map` has no semantics, but `IdNameMap` has. It's not just about making things shorter :) Furthermore, function parameters still need to be typed, and I'm moving more and more toward short functions. – Matthieu M. Apr 28 '12 at 20:18
  • To be be honest, I typedef every here and there too. But, this information (IdNameMap) can be but into the variable name. Also, it annoys me that my answer didn't get accepted as the correct one, as I think it's the best answer to this question :) – Viktor Sehr Apr 29 '12 at 11:55
  • Tastes vary :) I find your macro relatively elegant (not its name, which is a reserved identifier). My main peeve is that, really, `auto` should be supported here. After all, for predicates we can use template methods, so it's not like the compiler does not know how to deal with this... – Matthieu M. Apr 29 '12 at 12:00
  • I agree totally; I even had a question about this; http://stackoverflow.com/questions/5712826/argument-type-auto-deduction-and-anonymous-lambda-functions – Viktor Sehr Apr 29 '12 at 12:31
  • Imho, I think the reason we dont have this is because the standard commitee doesn't work with C++ on a daily basis, and therefor tend to focus on things like variadic templates (which, according to me, should have a lot lower priority). – Viktor Sehr Apr 29 '12 at 12:32
  • I would disagree wrt variadic templates :) As for lambdas, I believe it is a simple omission. I am afraid it would not make it into a DR though. – Matthieu M. Apr 29 '12 at 12:48