无法对具有公共字段的不同类型的结构应用std :: set_intersection

时间:2014-03-17 14:14:13

标签: c++ c++11 lambda stl set-intersection

我正在尝试使用 std::set_intersection 来查找具有共同绑定名称的两种完全不同类型的数据结构之间的共同元素。领域。

我查看了以下enter link description here,但它似乎迫使我沿着路线在我试图避免的两种不同结构类型之间进行自定义转换(因为这些类型来自第三方)< / p>

下面的代码段显示了我想要实现的目标。

// common field used for set intersection
typedef struct StructA {
    std::string mCommonField;
    float mFloatValue;
} StructA;

typedef struct StructB {
    std::string mCommonField;
    int mValue1;
    short mValue2;
} StructB;

// initially unsorted list
std::vector<StructA> aStructs = {{"hello", 1.0f}, {"goodbye", 2.0f}, {"foo", 3.0f}};
// initially unsorted list
std::vector<StructB> bStructs = {{"hello", 1, 2}, {"goodbye", 3, 4}, {"bar", 5, 6}};
// sorting both sets before calling std::intersection
std::sort(aStructs.begin(), aStructs.end(),
    [](const StructA& lhs, const StructA& rhs) {
        return lhs.mCommonField < rhs.mCommonField;
    });
std::sort(bStructs.begin(), bStructs.end(),
    [](const StructB& lhs, const StructB& rhs) {
    return lhs.mCommonField < rhs.mCommonField;
});

std::vector<StructA> intersection;
std::set_intersection(
    aStructs.begin(), aStructs.end(),
    bStructs.begin(), bStructs.end(),
    std::back_inserter(intersection),
    [](const StructA& lhs, const StructB& rhs){
        return lhs.mCommonField < rhs.mCommonField;
    });

我正在使用Visual Studio 2013来编译上面的内容,但是上面的代码会出现如下所示的大量错误。阅读 std::set_intersection ,我遇到了将兼容的 StrictWeakOrdering comp 最后一个参数放在一起的问题。理想情况下,我希望将其作为一个lambda实现。

template <class InputIterator1, class InputIterator2, class OutputIterator,
          class StrictWeakOrdering>
OutputIterator set_intersection(InputIterator1 first1, InputIterator1 last1,
                                InputIterator2 first2, InputIterator2 last2,
                                OutputIterator result, 
                                StrictWeakOrdering comp);
  

1&gt; C:\ Program Files(x86)\ Microsoft Visual Studio   12.0 \ VC \ include \ algorithm(3591):错误C2664:&#39; bool(__ vectorcall *)(const main :: StructA&amp;,const main :: StructB&amp;)&#39; :无法从&#39; main :: StructB&#39;转换参数1 to const const :: StructA&amp;&#39; 1 GT;
  原因:无法转换为&#39; main :: StructB&#39; to const const :: StructA&#39;   1 GT;没有可用的用户定义转换运算符   执行此转换,或者不能将操作员称为1>   C:\ Program Files(x86)\ Microsoft Visual Studio   12.0 \ VC \ include \ algorithm(3625):参见函数模板实例化&#39; _OutIt   的std :: _ Set_intersection&LT; _InIt1,_InIt2,_OutIt,_Pr&GT;(_ INIT1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr)&#39;   正在编译1&gt;用1> [1>   _OutIt =标准:: back_insert_iterator&GT;&GT;   1 GT; ,_InIt1 = main :: StructA * 1&gt; ,
  _InIt2 = main :: StructB * 1&gt; ,_Pr = main :: 1&gt; ] 1&gt; C:\ Program Files(x86)\ Microsoft Visual Studio   12.0 \ VC \ include \ algorithm(3654):参见函数模板实例化&#39; _OutIt   的std :: _ Set_intersection2(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr,性病:: true_type)&#39;   正在编译1&gt;用1> [1>   _OutIt =标准:: back_insert_iterator&GT;&GT;   1 GT; ,_Pr = main ::   1 GT; ,_InIt1 = main :: StructA * 1&gt; ,
  _InIt2 = main :: StructB * 1&gt; ] 1&gt; .... \ src \ dlf \ main.cpp(111):参见函数模板的引用   实例化&#39; _OutIt   的std :: set_intersection&GT;&GT;,的std :: _ Vector_iterator&GT;&GT;,的std :: back_insert_iterator&GT;&GT;,主::&GT;(_ INIT1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr)&#39;   正在编译1&gt;用1> [1>   _OutIt =标准:: back_insert_iterator&GT;&GT;   1 GT; ,_Ty = main :: StructA 1&gt; ,
  _InIt1 =标准:: _ Vector_iterator&GT;&GT;   1 GT; ,
  _InIt2 =标准:: _ Vector_iterator&GT;&GT;   1 GT; ,_Pr = main ::   1 GT; ]

我还尝试使用自定义比较器结构进行比较,但错误更令人困惑:

struct comparator {
    bool operator()(const StructA& lhs, const StructB& rhs) const {
        return lhs.mCommonField < rhs.mCommonField;
    }
    bool operator()(const StructB& lhs, const StructA& rhs) const {
        return lhs.mCommonField < rhs.mCommonField;
    }
};

std::vector<StructA> intersection;
std::set_intersection(
    aStructs.begin(), aStructs.end(),
    bStructs.begin(), bStructs.end(),
    std::back_inserter(intersection),
    comparator());

导致以下详细错误输出。我希望避免自定义结构(因为我试图使用的实际是来自第三方)从StructA到StructB的转换器,反之亦然,有什么方法可以避免这种情况,只是有一些简单的lambda实现两个相对简单的结构与一个共同字段之间的简单绑定?
提前谢谢。

  

1&gt; C:\ Program Files(x86)\ Microsoft Visual Studio   12.0 \ VC \ include \ xutility(521):错误C2664:&#39; bool main :: comparator :: operator()(const main :: StructA&amp;,const   main :: StructB&amp;)const&#39; :无法转换参数1   &#39;主:: StructA&#39; to const const :: StructB&amp;&#39; 1 GT;原因:不能   转换为&#39; main :: StructA&#39; to const const :: StructB&#39; 1 GT;没有   可以执行此操作的用户定义转换运算符   转换,或者操作员不能被称为1> C:\ PROGRAM   文件(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(625):   请参阅函数模板实例化&amp; bool的参考   的std :: _ Debug_lt_pred&LT; _Pr,主:: StructA&安培;,主:: StructA&安培;&GT;(_ PR,_Ty1,_Ty2,性病:: _ Dbfile_t,性病:: _ Dbline_t)&#39;   正在编译1&gt;用1> [1>   _Pr = main ::比较器1&gt; ,_Ty1 = main :: StructA&amp; 1 GT; ,_Ty2 = main :: StructA&amp; 1 GT; ] 1&gt; C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(636):参见   参考函数模板实例化&#39; void   的std :: _ Debug_order2&LT; _Init,_Pr&GT;(_ FwdIt,_FwdIt,_Pr,性病:: _ Dbfile_t,性病:: _ Dbline_t,性病:: forward_iterator_tag)&#39;   正在编译1&gt;用1> [1>   _Init =标准:: _ Vector_iterator&GT;&GT;   1 GT; ,_Pr = main ::比较器1&gt; ,
  _FwdIt =标准:: _ Vector_iterator&GT;&GT;   1 GT; ] 1&gt; C:\ Program Files(x86)\ Microsoft Visual   Studio 12.0 \ VC \ include \ algorithm(3649):参见函数参考   模板实例化&#39; void   的std :: _ Debug_order&LT; _InIt1,_Pr&GT;(_ INIT,_init,_Pr,性病:: _ Dbfile_t,性病:: _ Dbline_t)&#39;   正在编译1&gt;用1> [1>   _InIt1 =标准:: _ Vector_iterator&GT;&GT;   1 GT; ,_Pr = main ::比较器1&gt; ,
  _Init =标准:: _ Vector_iterator&GT;&GT;   1 GT; ] 1&gt; .... \ src \ dlf \ main.cpp(118):参见参考资料   功能模板实例化&#39; _OutIt   的std :: set_intersection&GT;&GT;,的std :: _ Vector_iterator&GT;&GT;,的std :: back_insert_iterator&GT;&GT;,主::比较&GT;(_ INIT1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr)&#39;   正在编译1&gt;用1> [1>   _OutIt =标准:: back_insert_iterator&GT;&GT;   1 GT; ,_Ty = main :: StructA 1&gt; ,
  _InIt1 =标准:: _ Vector_iterator&GT;&GT;   1 GT; ,
  _InIt2 =标准:: _ Vector_iterator&GT;&GT;   1 GT; ,_Pr = main ::比较器1&gt; ] 1&gt; C:\ Program Files   (x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(523):错误   C2664:&#39; bool main :: comparator :: operator()(const main :: StructA&amp;,const   main :: StructB&amp;)const&#39; :无法转换参数1   &#39;主:: StructA&#39; to const const :: StructB&amp;&#39; 1 GT;原因:不能   转换为&#39; main :: StructA&#39; to const const :: StructB&#39; 1 GT;没有   可以执行此操作的用户定义转换运算符   转换,或运算符不能被称为1> C:\ Program Files   (x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(521):错误   C2664:&#39; bool main :: comparator :: operator()(const main :: StructA&amp;,const   main :: StructB&amp;)const&#39; :无法转换参数2   &#39;主:: StructB&#39; to const const :: StructA&amp;&#39; 1 GT;原因:不能   转换自&#39; main :: StructB&#39; to const const :: StructA&#39; 1 GT;没有   可以执行此操作的用户定义转换运算符   转换,或者操作员不能被称为1> C:\ PROGRAM   文件(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(625):   请参阅函数模板实例化&amp; bool的参考   的std :: _ Debug_lt_pred&LT; _Pr,主:: StructB&安培;,主:: StructB&安培;&GT;(_ PR,_Ty1,_Ty2,性病:: _ Dbfile_t,性病:: _ Dbline_t)&#39;   正在编译1&gt;用1> [1>   _Pr = main ::比较器1&gt; ,_Ty1 = main :: StructB&amp; 1 GT; ,_Ty2 = main :: StructB&amp; 1 GT; ] 1&gt; C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(636):参见   参考函数模板实例化&#39; void   的std :: _ Debug_order2&LT; _Init,_Pr&GT;(_ FwdIt,_FwdIt,_Pr,性病:: _ Dbfile_t,性病:: _ Dbline_t,性病:: forward_iterator_tag)&#39;   正在编译1&gt;用1> [1>   _Init =标准:: _ Vector_iterator&GT;&GT;   1 GT; ,_Pr = main ::比较器1&gt; ,
  _FwdIt =标准:: _ Vector_iterator&GT;&GT;   1 GT; ] 1&gt; C:\ Program Files(x86)\ Microsoft Visual   Studio 12.0 \ VC \ include \ algorithm(3650):参见函数参考   模板实例化&#39; void   的std :: _ Debug_order&LT; _InIt2,_Pr&GT;(_ INIT,_init,_Pr,性病:: _ Dbfile_t,性病:: _ Dbline_t)&#39;   正在编译1&gt;用1> [1>   _InIt2 =标准:: _ Vector_iterator&GT;&GT;   1 GT; ,_Pr = main ::比较器1&gt; ,
  _Init =标准:: _ Vector_iterator&GT;&GT;   1 GT; ] 1&gt; C:\ Program Files(x86)\ Microsoft Visual Studio   12.0 \ VC \ include \ xutility(523):错误C2664:&#39; bool main :: comparator :: operator()(const main :: StructA&amp;,const   main :: StructB&amp;)const&#39; :无法转换参数2   &#39;主:: StructB&#39; to const const :: StructA&amp;&#39; 1 GT;原因:不能   转换自&#39; main :: StructB&#39; to const const :: StructA&#39; 1 GT;没有   可以执行此操作的用户定义转换运算符   转换,或者不能调用运算符

3 个答案:

答案 0 :(得分:12)

由于C ++的表现力,有几种方法可以解决这个问题。以下内容绝不是详尽的清单。

1。将两种类型隐式转换为包装结构以进行比较

如果您使用lambdas,请定义一个可以从StructAStructB隐式构造的类型,并包装用于比较的字段。这可以允许在比较之前对构造函数中的字段执行额外的逻辑。例如:

struct Common {
    std::string const& mCommonField;
    Common(StructA const& sa) : mCommonField{sa.mCommonField} {};
    Common(StructB const& sb) : mCommonField{sb.mCommonField} {};
};

然后你的比较lambda可以写成

auto cmp = [](Common const& lhs, Common const& rhs) {
    return lhs.mCommonField < rhs.mCommonField;
};

并使用

std::sort(aStructs.begin(), aStructs.end(), cmp);
std::sort(bStructs.begin(), bStructs.end(), cmp);
// ...
std::set_intersection(aStructs.begin(), aStructs.end(),
                      bStructs.begin(), bStructs.end(),
                      std::back_inserter(intersection),
                      cmp
                      );

Coliru Viewer上的实例。

2。使用带有模板化operator()的比较器。

不使用lambda,而是定义带有模板operator()的算器。

struct comparator
{
    template<typename T, typename U>
    bool operator()(T const& lhs, U const& rhs) const {
        return lhs.mCommonField < rhs.mCommonField;
    }
};

然后,它就像:

一样简单
std::sort(aStructs.begin(), aStructs.end(), comparator{});
std::sort(bStructs.begin(), bStructs.end(), comparator{});
// ...
std::set_intersection(aStructs.begin(), aStructs.end(),
                      bStructs.begin(), bStructs.end(),
                      std::back_inserter(intersection),
                      comparator{}
                      );

请注意,由于比较器中有模板,因此必须在函数范围之外声明。 Coliru Viewer上的实例。

3。等待C ++ 14

通过在C ++ 14中添加泛型lambda,您可以将以下内容与符合标准的编译器一起使用:

auto cmp = [](auto lhs, auto rhs) { return lhs.mCommonField < rhs.mCommonField; };
// ...
std::sort(aStructs.begin(), aStructs.end(), cmp);
std::sort(bStructs.begin(), bStructs.end(), cmp);
// ...
std::set_intersection(aStructs.begin(), aStructs.end(),
                      bStructs.begin(), bStructs.end(),
                      std::back_inserter(intersection),
                      cmp);

再次,Coliru Viewer上的实例。


此外,在C ++中不需要C风格的struct typedef(并且可以说在C中的大多数地方都不清楚),所以你可以在任何地方使用

typedef struct Foo {
    // ...
} Foo;

你可以用

替换它
struct Foo {
    // ...
};

不需要对代码进行任何其他更改。

答案 1 :(得分:0)

使用std :: copy_if和lambda,它使用std :: binary_search在vectorB中搜索 请务必使用您将给予binary_search的相同谓词进行排序

这解决了类似的问题: elegant way to remove all elements of a vector that are contained in another vector?

答案 2 :(得分:-2)

set_intersection并不神奇,如果你有自己的排序向量,你可以很容易地自己滚动,大概是这样的:

auto ta = aStructs.begin();
auto tb = bStructs.begin();
while( ta != aStructs.end() && tb != bStructs.end() ){
    if( ta->mCommonField < tb->mCommonField ){
        ++ta;
    } else if( tb->mCommonField < ta->mCommonField ){
        ++tb;
    } else {
        std::cout << "found common: " << ta->mCommonField << std::endl;
        ++ta;
        ++tb;
    }
}