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();
}

person cherry aldi    schedule 28.11.2018    source источник
comment
возможно, это бесполезно для вас, но... если вы хотите написать общий код, который работает для std::tuple и std::pair (также std::array, если хотите), вы можете использовать std::get() также для пар; поэтому для объекта p типа std::pair можно использовать std::get<0>(p) вместо p.first.   -  person max66    schedule 28.11.2018


Ответы (2)


std::find_if возвращает итератор в пару, поэтому вам нужно использовать оператор стрелки ->, который итератор перегрузил, чтобы вернуть ссылку на фактическое значение для целей доступа к членам.

Да, std::get<1> для кортежа будет делать почти то же самое, но синтаксис будет другим:

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

Вам нужно использовать оператор разыменования * вместо оператора стрелки, потому что std::get — это свободная функция, а не член кортежа.

person Bartek Banachewicz    schedule 28.11.2018

Документация по проверке 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& в большинстве случаев :), потому что мы не хотим делать копию здесь.

person Dawid Drozd    schedule 28.11.2018
comment
большое спасибо за ваше объяснение. Я читаю о std::find(). Я опубликовал второй пример в своем первоначальном вопросе, следуя вашему совету, однако он неверен, не могли бы вы подсказать, что я сделал неправильно? благодарю вас - person cherry aldi; 28.11.2018
comment
@cherryaldi Я добавил исправление для вашего второго примера. Если это все еще не работает, пожалуйста, дайте больше информации, что не работает? Возможно добавить ошибки компиляции. - person Dawid Drozd; 29.11.2018