2

I'm converting this function to use std::tuple which does not have first and second memebers like std:pair.

std::type_index argumentType(const std::string& name) const
{
    return std::find_if(args_.begin(), args_.end(),
        [&name](std::pair<std::string, std::type_index> arg)->bool
        {
            return arg.first == name;
        }
    )->second;
}

I'm confused by the syntax ->second, what is this doing? and is thre equivalent std::get<1>(arg)

std::type_index argType(const std::string& name) const
{
    return std::find_if(args_.begin(), args_.end(),
        [&name](std::tuple<std::string, std::type_index, Attribute> arg)->bool
        {
            return std::get<0>(arg) == name;
        }
    )std::get<1>(arg);

Example 2:

std::pair

bool hasArg(const std::string& name) const
{
    return std::find_if(args_.begin(), args_.end(),
        [&name](std::pair<std::string, std::type_index> arg)->bool
        {
            return arg.first == name;
        }
    ) != args_.end();
}

std::tuple

bool hasArg(const std::string& name) const
{
    return std::get<0>(*std::find_if(args_.begin(), args_.end(),
        [&name](std::tuple<std::string, std::type_index, Attribute> arg)->bool
        {
            return std::get<0>(arg) == name;
        }
    )) != args_.end();
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
cherry aldi
  • 327
  • 1
  • 10
  • 1
    maybe isn't useful for you but... if you want to write a common code that works for `std::tuple` and `std::pair` (also `std::array`, if you want) you can use `std::get()` also for pairs; so, for a `p` object of a `std::pair` type, you can use `std::get<0>(p)` instead of `p.first`. – max66 Nov 28 '18 at 17:55

2 Answers2

1

std::find_if returns an iterator to a pair, that's why you need to use the arrow operator ->, which the iterator has overloaded to return a reference to the actual value for purposes of member access.

Yes, std::get<1> for a tuple will do pretty much the same, but the syntax will be different:

auto it = std::find_if(...);
return std::get<1>(*it);

You need to use the dereference operator * instead of the arrow operator, because std::get is a free function and not a tuple's member.

Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
1

Checkout documentation of std::find_if

So std::find_if will return iterator. In code #1 it was iterator to pair, so ->second will husk second element of std::pair. You use -> overloaded operator for iterator.

Example:

auto it = std::find_if(args_.begin(), args_.end(),...);
if(it != args_.end()) // This is important to NOT dereference iterator if it is pointing to end
{
    // also you can write (*it).second; (first use dereference operator)
    return it->second;
}
// ...

So in you case you should refactor it to:

std::type_index argType(const std::string& name) const
{
    // Please don't do so much in 1 line. Compiler will optimize this for you :)
    // Please check for std::end, this is potential dangerous.
    return std::get<1>(*std::find_if(args_.begin(), args_.end(),
        [&name](std::tuple<std::string, std::type_index, Attribute> arg)->bool
        {
            return std::get<0>(arg) == name;
        }
    ));
}

Same example:

auto it = std::find_if(args_.begin(), args_.end(),...);
if(it != args_.end()) // This is important to NOT dereference iterator if it is pointing to end
{
    return std::get<1>(*it);
}
// ...

Important

Please also consider case when you don't find your element. std::find_if will return std::end(args_) if element you are looking for doesn't exist. So calling ->second or std::get<1>(*it) is undefinied behaviour and can crush.


Fix for hasArg function. Now you don't need dereference your iterator.

bool hasArg(const std::string& name) const
{
    return std::find_if(std::begin(args_), std::end(args_),
        [&name](const std::tuple<std::string, std::type_index, Attribute>& arg)->bool
        {
            return std::get<0>(arg) == name;
        }
    ) != std::end(args_);
}

In this solution I used std::begin and std::end. This is more uniwersal way instead calling arg_.begin() :)

Please check how I ficed syntax of your second example. One last thing, when you use std::find_if and lambda to find what you are looking for, argument should be const& in most cases :), because we don't want to make a copy here.

Gelldur
  • 11,187
  • 7
  • 57
  • 68
  • many thanks for you explanation. I am reading about `std::find()`. I've posted a second example in my original question following your advice however it is not correct, could you suggest what I've done wrong? thank you – cherry aldi Nov 28 '18 at 16:12
  • @cherryaldi I added fix for your second example. If it still doesn't work please give more information what isn't working ? Maybe add compilation errors. – Gelldur Nov 29 '18 at 08:29