【问题标题】:Error when using lower_bound with vector<pair<string, double>>将 lower_bound 与 vector<pair<string, double>> 一起使用时出错
【发布时间】:2013-11-25 16:48:13
【问题描述】:

我有一个缓存的实现,它是这样定义的;

std::vector<TEntryPair>    m_listEntries;

TEntryPair 被定义为;

typedef std::pair<std::string, FILETIME> TEntryPair;

将新记录插入缓存时,我使用std::lower_bound 在缓存中找到正确的位置以进行插入排序,如下所示;

void AddCacheEntry(std::string const& strResourceName, FILETIME const& fTime)
{
    auto it = std::lower_bound(std::begin(m_listEntries),
                               std::end(m_listEntries),
                               strName);

    m_listEntries.insert(it, std::make_pair(strName, fTime));
}

新条目根据std::string参数进行插入排序,第二个值基本上是元数据。

我为std::lower_bound 定义了以下运算符,以便在尝试插入新记录时使用;

bool operator < (std::string const& str, TEntryPair const& rhs)
{
    return str < rhs.first;
}
bool operator < (TEntryPair const& lhs, std::string const& str)
{
    return lhs.first < str;
}

现在一切正常,直到我不得不将 TEntryPair 的定义更改为以下内容;

std::pair<std::string, double>

有人可以解释为什么我定义的运算符在使用std::pair&lt;std::string, double&gt; 而不是std::pair&lt;std::string, FILETIME&gt; 时无法使用吗?

编译器给出以下错误;

Error   9   error C2676: binary '<' : 'std::pair<_Ty1,_Ty2>' does not define this operator or a conversion to a type acceptable to the predefined operator  c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm    2736
Error   3   error C2784: 'bool std::operator <(const _Elem *,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'const _Elem *' from 'std::pair<_Ty1,_Ty2>' c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm    2736
Error   7   error C2784: 'bool std::operator <(const std::_Revranit<_RanIt,_Base> &,const std::_Revranit<_RanIt2,_Base2> &)' : could not deduce template argument for 'const std::_Revranit<_RanIt,_Base> &' from 'std::pair<_Ty1,_Ty2>'    c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm    2736
Error   2   error C2784: 'bool std::operator <(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'std::pair<_Ty1,_Ty2>'   c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm    2736
Error   4   error C2784: 'bool std::operator <(const std::basic_string<_Elem,_Traits,_Alloc> &,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'std::pair<_Ty1,_Ty2>' c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm    2736
Error   5   error C2784: 'bool std::operator <(const std::move_iterator<_RanIt> &,const std::move_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::move_iterator<_RanIt> &' from 'std::pair<_Ty1,_Ty2>'   c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm    2736
Error   8   error C2784: 'bool std::operator <(const std::pair<_Ty1,_Ty2> &,const std::pair<_Ty1,_Ty2> &)' : could not deduce template argument for 'const std::pair<_Ty1,_Ty2> &' from 'const std::string' c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm    2736
Error   6   error C2784: 'bool std::operator <(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'std::pair<_Ty1,_Ty2>'  c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm    2736
Error   1   error C2784: 'bool std::operator <(const std::vector<_Ty,_Alloc> &,const std::vector<_Ty,_Alloc> &)' : could not deduce template argument for 'const std::vector<_Ty,_Alloc> &' from 'std::pair<_Ty1,_Ty2>' c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm    2736

顺便说一句,我可以定义以下内容并编译/运行代码而不会出现任何错误;

struct STemp
{
    double m_Value;
}

typedef std::pair<std::string, STemp> TEntryPair;

似乎只是“基本”类型有问题?

【问题讨论】:

  • 您是否也将 AddCacheEntry 更改为具有 double 类型的第二个参数?
  • @zennehoy 是的,我已经更新了定义。
  • 如果两个都定义了operator &lt;,std::pair 是否不会自动从其“成员”中推断出operator &lt;?就像内置类型的情况一样。
  • 附录:在这种情况下,您可以使用比较器作为lowerBound 的第四个参数,而不是定义另一个operator &lt;。它实际上也会更有意义。

标签: c++ vector stl stdstring lower-bound


【解决方案1】:

罪魁祸首似乎是 c++ 名称解析(特别是参数相关查找)与标准库中预定义的运算符

如果 TEntryPair 完全位于标准库中,将找不到顶级命名空间中的 operator

虽然标准明确规定不允许重载命名空间 std 中的函数,但我能够找到的唯一解决方案是将 operator

对于符合标准的解决方案,您可能需要定义自己的类,而不是使用 std::pair。

#include <vector>
#include <algorithm>
#include <string>

typedef double MyType;

struct TEntryPair {
    std::string first;
    MyType second;
};

bool operator < (std::string const& str, TEntryPair const& rhs)
{
    return str < rhs.first;
}
bool operator < (TEntryPair const& lhs, std::string const& str)
{
    return lhs.first < str;
}

std::vector<TEntryPair>    m_listEntries;

void AddCacheEntry(std::string const& strResourceName, MyType fTime)
{
    auto it = std::lower_bound(std::begin(m_listEntries),
                               std::end(m_listEntries),
                               strResourceName);
}

int main() { }

【讨论】:

  • 正确答案,错误解决方案“要解决问题,请将运算符。虽然不应将重载放在命名空间std、[namespace.std]/1 中。 (如果没有明确允许的话,至少不会。)
  • @DyP:为此添加了一条声明,但我无法找到解决问题的其他方法。标准库不足?你对如何解决它有什么建议吗?
  • 虽然可行,但它并不是@DyP 提到的理想解决方案。使用上面一些链接问题的建议,我设法获得了某种形式的解决方案 - 我已将其添加为对原始问题的编辑。虽然它看起来有点……不优雅……对我来说。
  • 啊!我没有看到你正在编辑,因为我一直在编辑我的原始帖子。你的解决方案更干净!我向 TEntryPair 结构添加了一个构造函数,以便我可以按如下方式执行插入; m_listEntries.insert(它, TEntryPair(strName, 0.1));这是最干净的方法吗?或者有没有办法使用新的 c++11 初始化列表?
  • @Ralara 是的,没关系。如果使用 c++11,您也可以使用 m_listEntries.insert(it, {strName, 0.1}),即使没有显式定义构造函数。
猜你喜欢
  • 2012-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-21
  • 2021-04-23
  • 2018-04-22
相关资源
最近更新 更多