Эквивалент std::tuple второго члена std::pair?
Я конвертирую эту функцию для использования std::tuple
который не имеет first
а также second
как члены 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;
}
Я смущен синтаксисом ->second
что это делает? и является эквивалентным 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);
Пример 2:
станд:: пара
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();
}
станд:: кортеж
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();
}
2 ответа
std::find_if
возвращает итератор для пары, поэтому вам нужно использовать оператор стрелки ->
, который итератор перегружен, чтобы вернуть ссылку на фактическое значение для целей доступа к элементу.
Да, std::get<1>
для кортежа будет делать то же самое, но синтаксис будет другим:
auto it = std::find_if(...);
return std::get<1>(*it);
Вам нужно использовать оператор разыменования *
вместо оператора стрелки, потому что std::get
это свободная функция, а не член кортежа.
Оформление документации по std::find_if
Так std::find_if
вернет итератор. В коде № 1 это был итератор для сопряжения, поэтому ->second
будет шелуха second
элемент std:: pair. Вы используете -> перегруженный оператор для итератора.
Пример:
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;
}
// ...
Так что в вашем случае вы должны изменить его на:
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;
}
));
}
Тот же пример:
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);
}
// ...
Важный
Пожалуйста, рассмотрите также случай, когда вы не нашли свой элемент. std::find_if
вернусь std::end(args_)
если элемент, который вы ищете, не существует. Так зовет ->second
или же std::get<1>(*it)
является неопределенным поведением и может сокрушить.
Исправить для hasArg
функция. Теперь вам не нужно разыменовывать свой итератор.
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_);
}
В этом решении я использовал std:: begin и std:: end. Это более универсальный способ вместо вызова arg_.begin()
:)
Пожалуйста, проверьте, как я определил синтаксис вашего второго примера. И последнее, когда вы используете std::find_if
и лямбда, чтобы найти то, что вы ищете, аргумент должен быть const&
в большинстве случаев:), потому что мы не хотим делать копию здесь.