std :: tuple等同于std :: pair的第二个成员?

时间:2018-11-28 15:22:51

标签: c++ c++11 iterator std-pair stdtuple

我正在将该函数转换为使用std::tuplefirst这样的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:

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

2 个答案:

答案 0 :(得分:1)

std::find_if将一个迭代器返回到一对,这就是为什么您需要使用箭头运算符->的原因,该迭代器已重载以返回对实际值的引用以用于成员访问。 / p>

是的,std::get<1>对于元组的作用几乎相同,但语法会有所不同:

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

您需要使用取消引用运算符*而不是箭头运算符,因为std::get是自由函数,不是元组的成员。

答案 1 :(得分:1)

std::find_if的结帐文档

因此std::find_if将返回迭代器。在代码#1中,iterator是配对的,因此->second将剥去std::pairsecond元素。您使用-> overloaded operator for iterator

示例:

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_)。因此,调用->secondstd::get<1>(*it) is undefinied behaviour可能会崩溃。


修复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::beginstd::end。这是更普遍的方式,而不是调用arg_.begin():)

请检查我如何调整第二个示例的语法。 最后一件事,当您使用std::find_if和lambda来查找所需内容时,在大多数情况下,参数应该为const& :),因为我们不想在此处复制。