3

我试图让includes算法在 a 上工作,set并将map地图的键与集合的值进行比较。需要规避的问题当然map<K,V>::value_typepair<K,V>while set<V>::value_typeisV所以这些不适用于默认值,默认值includes predicate<T>期望两个参数具有相同的值类型。

因此,我正在编写以下谓词类来解决这个问题

template <class P,class K>
struct mapKey_set_less : public std::binary_function<P,K,bool>
{
   inline bool operator() (const P& x, const K& y) const {return x.first < y ;};
};

template <class K,class P>
struct set_mapKey_less : public std::binary_function<K,P,bool>
{
    inline bool operator() (const K& x, const P& y) const {return x < y.first ;};
};

然而,模板实例化器在 VS2008 xutility 文件的第 313 行抛出

if (!_Pred(_Left, _Right))

带有无法将参数 1 从转换为的const V消息const std::pair<_Ty1,_Ty2>

这似乎是由文件的第 3795 行引起的

if (_DEBUG_LT_PRED(_Pred, *_First2, *_First1))

其中第一个和第二个参数似乎已被交换 在发布配置中编译在第 3795 行给出了相同的错误,因此 Visual Studio 实现似乎希望您通过此代码,除非您修改任何开关(如果有)删除此' _DEBUG_LT_PRED' 宏。

我的问题是:这是 Visual Studio 中的一个错误,还是有这样的原因,我犯了一个错误?十多年来,我没有做过任何 C++,上周不得不重新开始,以便在一些紧凑的循环中加快速度,所以需要我能得到的所有帮助。

谢谢大家

好的,

我没有考虑算法的要求。有道理,它需要从双方检查“小于”。

虽然编译这个并没有得到太多的乐趣。

用我以前的代码

template <class P,class K>
struct mapKey_set_cmp //: public std::binary_function<P,K,bool>
{
    inline bool operator() (const P& x, const K& y) const {return x.first < y ;};
};

我得到

error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const P &,const K &) const' : 
cannot convert parameter 1 from 'const double' to 'const std::pair<_Ty1,_Ty2> &'

这是有道理的,因为没有 operator() 可以将 double 作为其第一个参数。

使用额外的重载 operator()

template <class P,class K>
struct mapKey_set_cmp //: public std::binary_function<P,K,bool>
{
    inline bool operator() (const P& x, const K& y) const {return x.first < y ;};
    inline bool operator() (const K& x, const P& y) const {return x < y.first ;};
};

我现在得到

error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' : 
cannot convert parameter 1 from 'const std::pair<_Ty1,_Ty2>' to 'const double &'

error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' : 
cannot convert parameter 1 from 'const std::pair<_Ty1,_Ty2>' to 'const double &'

error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' : 
cannot convert parameter 2 from 'const double' to 'const std::pair<_Ty1,_Ty2> &'

error C2664: 'bool mapKey_set_cmp<P,K>::operator ()(const K &,const P &) const' : 
cannot convert parameter 2 from 'const double' to 'const std::pair<_Ty1,_Ty2> &'

值得注意的是,所有错误似乎都与第 2 个错误有关operator(),即K第 1 个和P第 2 个错误。是的,在那个操作符上,所提到的任何转换都不应该是可能的。但是为什么编译器不尝试另一个运算符呢?即应该允许这些转换的那个。(顺便说一句,错误会重复出现,因为如果您想知道它们每个都出现在两条不同的行上)

这可能是另一件事当然是 const 不正确。已经有一段时间了,所以我会尝试考虑一下。

谢谢您的帮助

2013 年 5 月 15 日编辑

我不得不“继续下去”,所以通过将我的地图键放入一个集合中来规避这个问题,这样我就可以includes在两个集合上调用算法(导致明显的性能损失)。我仍然想正确解决这个问题。这是复制我用 Visual Studio 2008 描述的编译器错误所需的所有代码

template <class PAIR,class KEY>
struct mapKey_set_less : public std::binary_function<PAIR,KEY,bool>
{
    inline bool operator() (const PAIR& x, const KEY& y) const {return x.first < y ;};
    inline bool operator() (const KEY& x, const PAIR& y) const {return x < y.first ;};
};

int _tmain(int argc, _TCHAR* argv[])
{
    map<string,double> theMap;
    theMap["arse"] = 1;

    set<string> theSet;
    theSet.insert("arse");

    typedef map<string,double>::iterator MI;
    MI mi(theMap.begin()), miend(theMap.end());

    typedef set<string>::iterator SI;
    SI si(theSet.begin()), siend(theSet.end());

    typedef mapKey_set_less< pair<string,double>,string> cmp;

    if (includes(mi,miend,si,siend,cmp()))
    {}

}

编译器吐出来

Error   1   error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 1 from 'std::pair<_Ty1,_Ty2>' to 'const std::string &'    c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility  346
Error   2   error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 1 from 'std::pair<_Ty1,_Ty2>' to 'const std::string &'    c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility  348
Error   3   error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 2 from 'std::basic_string<_Elem,_Traits,_Ax>' to 'const std::pair<_Ty1,_Ty2> &'   c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility  346
Error   4   error C2664: 'bool mapKey_set_less<PAIR,KEY>::operator ()(const KEY &,const PAIR &) const' : cannot convert parameter 2 from 'std::basic_string<_Elem,_Traits,_Ax>' to 'const std::pair<_Ty1,_Ty2> &'   c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility  348

单看第一个错误,它似乎想使用 operator()(KEY,PAIR) 来传递 PAIR,KEY。为什么它忽略了可用的 operator()(PAIR,KEY)??? 其他错误都是一样的,编译器“似乎”忽略了一个完美的重载运算符

谢谢大家的帮助

4

1 回答 1

2

标准没有要求第一个范围内的对象只能作为比较函数的左侧参数传递,第二个范围内的对象也只能作为右侧参数传递。因此,Visual Studio 正在做的事情是完全有效的,而且通常是必要的(见下文)。

您可以做的是编写一个处理这两种情况的函子:

template <class K,class P>
struct set_mapKey_less : public std::binary_function<K,P,bool>
{
    inline bool operator() (const K& x, const P& y) const {return x < y.first;};
    inline bool operator() (const P& y, const K& x) const {return y.first < x; }
};
...
std::map<int,int> m;
std::set<int> s;

std::includes(m.begin(), m.end(), s.begin(), s.end(),
              set_mapKey_less<int,std::pair<int const,int> >());

要了解为什么 VS 正在执行的检查可能是必要的,请考虑以下几点:

set X = { 1000, 3000, 5000, 7000, 9000 }
map Y = { (3000,'a') }

如果你所拥有的只是一个小于运算符,它在左边取一对值,在右边取一个整数,你将如何测试 X 是否包含 Y?

Is (3000,'a').first < 1000? No.
Is (3000,'a').first < 3000? No.
Is (3000,'a').first < 5000? Yes.

此时,我们知道(3000,'a').first,如果在集合中,必须是 3000。但是我们如何使用只能取左侧对的比较器来测试它实际上是 3000?如果我们可以反转论点,我们可以做到:

Is 3000 < (3000,'a').first? No.

所以现在我们知道3000不小于(3000,'a').first,并且(3000,'a').first不小于3000,因此它们必须相等。

于 2013-02-07T01:47:00.800 回答