无法在具有公共字段的不同类型的结构上应用std :: set_intersection [英] unable to apply std::set_intersection on different types of structs with a common field

查看:107
本文介绍了无法在具有公共字段的不同类型的结构上应用std :: set_intersection的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正尝试使用 std :: set_intersection 来查找2种完全不同类型的数据结构之间的共同元素,这些数据结构具有共同的绑定名称"字段.

I am trying to use use std::set_intersection to find common elements between 2 completely different types of data structures that have a common binding 'name' field.

我查看了以下在此处输入链接说明,但这似乎迫使我沿途尝试在我试图避免的2种不同结构类型之间进行自定义转换(因为这些类型来自第三者)

I looked at the following enter link description here but it seems to force me down the route to do a custom conversion between the 2 different struct types which I was trying to avoid (as these types are from a 3rd party)

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

The code snippet below shows what I am trying to achieve.

// 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.

I am using Visual Studio 2013 to compile the above, however the above code spits out a plethora of errors as shown below. Reading through the std::set_intersection I am having a problem putting together a compatible StrictWeakOrdering comp last argument. I would ideally like to implement this as a one off 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> C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ algorithm(3591):错误C2664:'布尔(__vectorcall *)(const main :: StructA&,const main :: StructB&)':无法将参数1从'main :: StructB'转换改为"const main :: StructA&" 1>
原因:无法从"main :: StructB"转换为"const main :: StructA" 1>没有可用的用户定义转换运算符 执行此转换,否则无法调用运算符1>
C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ algorithm(3625):请参见对函数模板实例化'_OutIt的引用 std :: _ Set_intersection< _InIt1,_InIt2,_OutIt,_Pr>(_ InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr)' 正在被1>编译为1> [1>
_OutIt = std :: back_insert_iterator >> 1>,_InIt1 = main :: StructA * 1>,
_InIt2 = main :: StructB * 1>,_Pr = main :: 1>] 1> C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ algorithm(3654):请参见对功能模板实例化'_OutIt的引用 std :: _ Set_intersection2(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr,std :: true_type)' 正在被1>编译为1> [1>
_OutIt = std :: back_insert_iterator >> 1>,_Pr = main :: 1>,_InIt1 = main :: StructA * 1>,
_InIt2 = main :: StructB * 1>] 1> .... \ src \ dlf \ main.cpp(111):请参见对功能模板的引用 实例化'_OutIt std :: set_intersection >>,std :: _ Vector_iterator >>,std :: back_insert_iterator >>,main ::>((_ InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr)' 正在被1>编译为1> [1>
_OutIt = std :: back_insert_iterator >> 1>,_Ty = main :: StructA 1>,
_InIt1 = std :: _ Vector_iterator >> 1>,
_InIt2 = std :: _ Vector_iterator >> 1>,_Pr = main :: 1>]

1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\algorithm(3591): error C2664: 'bool (__vectorcall *)(const main::StructA &,const main::StructB &)' : cannot convert argument 1 from 'main::StructB' to 'const main::StructA &' 1>
Reason: cannot convert from 'main::StructB' to 'const main::StructA' 1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 1>
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\algorithm(3625) : see reference to function template instantiation '_OutIt std::_Set_intersection<_InIt1,_InIt2,_OutIt,_Pr>(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr)' being compiled 1> with 1> [ 1>
_OutIt=std::back_insert_iterator>> 1> , _InIt1=main::StructA * 1> ,
_InIt2=main::StructB * 1> , _Pr=main:: 1> ] 1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\algorithm(3654) : see reference to function template instantiation '_OutIt std::_Set_intersection2(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr,std::true_type)' being compiled 1> with 1> [ 1>
_OutIt=std::back_insert_iterator>> 1> , _Pr=main:: 1> , _InIt1=main::StructA * 1> ,
_InIt2=main::StructB * 1> ] 1> ....\src\dlf\main.cpp(111) : see reference to function template instantiation '_OutIt std::set_intersection>>,std::_Vector_iterator>>,std::back_insert_iterator>>,main::>(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr)' being compiled 1> with 1> [ 1>
_OutIt=std::back_insert_iterator>> 1> , _Ty=main::StructA 1> ,
_InIt1=std::_Vector_iterator>> 1> ,
_InIt2=std::_Vector_iterator>> 1> , _Pr=main:: 1> ]

我还尝试使用自定义比较器结构进行比较,但按照以下方法,错误甚至更加令人困惑:

I also tried to use a custom comparator struct to do the comparison, but the errors were even more confusing as per:

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在两个具有公共字段的相对简单的结构之间实现简单的绑定?
预先感谢.

which resulted in the following verbose error output. I was hoping to avoid customizing the structures (as the actual ones I am trying to use are from a 3rd party) to have converters from StructA to StructB and vise-versa, is there any way I can avoid that and just have some simple lambda to achieve a simple binding between 2 relatively simple structs with a common field?
Thanks in advance.

1> C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(521):错误C2664:'bool main :: comparator :: operator()(const main :: StructA&,const main :: StructB&)const':无法将参数1转换为 'main :: StructA'到'const main :: StructB&' 1>原因:不能 从'main :: StructA'转换为'const main :: StructB'1>否 可以执行此操作的用户定义的转换运算符 转换,否则无法调用运算符1> C:\ Program 文件(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(625): 请参见对功能模板实例化的参考 std :: _ Debug_lt_pred< _Pr,main :: StructA&,main :: StructA&>(_ Pr,_Ty1,_Ty2,std :: _ Dbfile_t,std :: _ Dbline_t)' 正在被1>编译为1> [1>
_Pr = main :: comparator 1>,_Ty1 = main :: StructA& 1>,_Ty2 = main :: StructA& 1>] 1> C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(636):请参阅 引用功能模板实例化'void std :: _ Debug_order2< _InIt,_Pr>(_ FwdIt,_FwdIt,_Pr,std :: _ Dbfile_t,std :: _ Dbline_t,std :: forward_iterator_tag)) 正在被1>编译为1> [1>
_InIt = std :: _ Vector_iterator >> 1>,_Pr = main :: comparator 1>,
_FwdIt = std :: _ Vector_iterator >> 1>] 1> C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ algorithm(3649):请参见对函数的引用 模板实例化'void std :: _ Debug_order< _InIt1,_Pr>(_ InIt,_InIt,_Pr,std :: _ Dbfile_t,std :: _ Dbline_t)' 正在被1>编译为1> [1>
_InIt1 = std :: _ Vector_iterator >> 1>,_Pr = main :: comparator 1>,
_InIt = std :: _ Vector_iterator >> 1>] 1> .... \ src \ dlf \ main.cpp(118):请参阅参考 功能模板实例化'_OutIt std :: set_intersection >>,std :: _ Vector_iterator >>,std :: back_insert_iterator >>,main :: comparator>(_ InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr)' 正在被1>编译为1> [1>
_OutIt = std :: back_insert_iterator >> 1>,_Ty = main :: StructA 1>,
_InIt1 = std :: _ Vector_iterator >> 1>,
_InIt2 = std :: _ Vector_iterator >> 1>,_Pr = main :: comparator 1>] 1> C:\ Program Files (x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(523):错误 C2664:'bool main :: comparator :: operator()(const main :: StructA&,const main :: StructB&)const':无法将参数1转换为 'main :: StructA'到'const main :: StructB&' 1>原因:不能 从'main :: StructA'转换为'const main :: StructB'1>否 可以执行此操作的用户定义的转换运算符 转换,否则无法将运算符称为1> C:\ Program Files (x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(521):错误 C2664:'bool main :: comparator :: operator()(const main :: StructA&,const main :: StructB&)const':无法将参数2转换为 'main :: StructB'到'const main :: StructA&' 1>原因:不能 从'main :: StructB'转换为'const main :: StructA'1>否 可以执行此操作的用户定义的转换运算符 转换,否则无法调用运算符1> C:\ Program 文件(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(625): 请参阅对功能模板实例化的参考 std :: _ Debug_lt_pred< _Pr,main :: StructB&,main :: StructB&>(_ Pr,_Ty1,_Ty2,std :: _ Dbfile_t,std :: _ Dbline_t)' 正在被1>编译为1> [1>
_Pr = main :: comparator 1>,_Ty1 = main :: StructB& 1>,_Ty2 = main :: StructB& 1>] 1> C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(636):请参阅 引用功能模板实例化'void std :: _ Debug_order2< _InIt,_Pr>(_ FwdIt,_FwdIt,_Pr,std :: _ Dbfile_t,std :: _ Dbline_t,std :: forward_iterator_tag)) 正在被1>编译为1> [1>
_InIt = std :: _ Vector_iterator >> 1>,_Pr = main :: comparator 1>,
_FwdIt = std :: _ Vector_iterator >> 1>] 1> C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ algorithm(3650):请参见对函数的引用 模板实例化'void std :: _ Debug_order< _InIt2,_Pr>(_ InIt,_InIt,_Pr,std :: _ Dbfile_t,std :: _ Dbline_t)' 正在被1>编译为1> [1>
_InIt2 = std :: _ Vector_iterator >> 1>,_Pr = main :: comparator 1>,
_InIt = std :: _ Vector_iterator >> 1>] 1> C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(523):错误C2664:'bool main :: comparator :: operator()(const main :: StructA&,const main :: StructB&)const':无法将参数2转换为 'main :: StructB'到'const main :: StructA&' 1>原因:不能 从'main :: StructB'转换为'const main :: StructA'1>否 可以执行此操作的用户定义的转换运算符 转换,否则无法调用运算符

1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xutility(521): error C2664: 'bool main::comparator::operator ()(const main::StructA &,const main::StructB &) const' : cannot convert argument 1 from 'main::StructA' to 'const main::StructB &' 1> Reason: cannot convert from 'main::StructA' to 'const main::StructB' 1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xutility(625) : see reference to function template instantiation 'bool std::_Debug_lt_pred<_Pr,main::StructA&,main::StructA&>(_Pr,_Ty1,_Ty2,std::_Dbfile_t,std::_Dbline_t)' being compiled 1> with 1> [ 1>
_Pr=main::comparator 1> , _Ty1=main::StructA & 1> , _Ty2=main::StructA & 1> ] 1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xutility(636) : see reference to function template instantiation 'void std::_Debug_order2<_InIt,_Pr>(_FwdIt,_FwdIt,_Pr,std::_Dbfile_t,std::_Dbline_t,std::forward_iterator_tag)' being compiled 1> with 1> [ 1>
_InIt=std::_Vector_iterator>> 1> , _Pr=main::comparator 1> ,
_FwdIt=std::_Vector_iterator>> 1> ] 1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\algorithm(3649) : see reference to function template instantiation 'void std::_Debug_order<_InIt1,_Pr>(_InIt,_InIt,_Pr,std::_Dbfile_t,std::_Dbline_t)' being compiled 1> with 1> [ 1>
_InIt1=std::_Vector_iterator>> 1> , _Pr=main::comparator 1> ,
_InIt=std::_Vector_iterator>> 1> ] 1> ....\src\dlf\main.cpp(118) : see reference to function template instantiation '_OutIt std::set_intersection>>,std::_Vector_iterator>>,std::back_insert_iterator>>,main::comparator>(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_Pr)' being compiled 1> with 1> [ 1>
_OutIt=std::back_insert_iterator>> 1> , _Ty=main::StructA 1> ,
_InIt1=std::_Vector_iterator>> 1> ,
_InIt2=std::_Vector_iterator>> 1> , _Pr=main::comparator 1> ] 1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xutility(523): error C2664: 'bool main::comparator::operator ()(const main::StructA &,const main::StructB &) const' : cannot convert argument 1 from 'main::StructA' to 'const main::StructB &' 1> Reason: cannot convert from 'main::StructA' to 'const main::StructB' 1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xutility(521): error C2664: 'bool main::comparator::operator ()(const main::StructA &,const main::StructB &) const' : cannot convert argument 2 from 'main::StructB' to 'const main::StructA &' 1> Reason: cannot convert from 'main::StructB' to 'const main::StructA' 1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xutility(625) : see reference to function template instantiation 'bool std::_Debug_lt_pred<_Pr,main::StructB&,main::StructB&>(_Pr,_Ty1,_Ty2,std::_Dbfile_t,std::_Dbline_t)' being compiled 1> with 1> [ 1>
_Pr=main::comparator 1> , _Ty1=main::StructB & 1> , _Ty2=main::StructB & 1> ] 1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xutility(636) : see reference to function template instantiation 'void std::_Debug_order2<_InIt,_Pr>(_FwdIt,_FwdIt,_Pr,std::_Dbfile_t,std::_Dbline_t,std::forward_iterator_tag)' being compiled 1> with 1> [ 1>
_InIt=std::_Vector_iterator>> 1> , _Pr=main::comparator 1> ,
_FwdIt=std::_Vector_iterator>> 1> ] 1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\algorithm(3650) : see reference to function template instantiation 'void std::_Debug_order<_InIt2,_Pr>(_InIt,_InIt,_Pr,std::_Dbfile_t,std::_Dbline_t)' being compiled 1> with 1> [ 1>
_InIt2=std::_Vector_iterator>> 1> , _Pr=main::comparator 1> ,
_InIt=std::_Vector_iterator>> 1> ] 1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xutility(523): error C2664: 'bool main::comparator::operator ()(const main::StructA &,const main::StructB &) const' : cannot convert argument 2 from 'main::StructB' to 'const main::StructA &' 1> Reason: cannot convert from 'main::StructB' to 'const main::StructA' 1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

推荐答案

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

Thanks to the expressiveness of C++, there are a few ways you can solve this problem. The following is by no means an exhaustive list.

如果您喜欢使用lambda,请定义一个可以同时从StructAStructB隐式构造的类型,并包装用于比较的字段.这可以允许在比较之前对构造函数中的字段执行其他逻辑.例如:

If you're attached to using lambdas, define a type that can be implicitly constructed from both StructA and StructB and wraps the fields used for comparison. This can allow for additional logic to be performed to the fields in the constructor before comparison. For example:

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

然后您可以编写比较lambda

Then your comparison lambda can be written

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 上的实时示例.

使用模板化的operator()定义函子,而不是使用lambda.

Instead of using a lambda, define a functor with a templated 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 上的实时示例.

Just note that as there is a template in the comparator, it must be declared outside of function scope. Live example on Coliru Viewer.

在C ++ 14中添加了通用lambda之后,您可以将以下代码与兼容的编译器一起使用:

And with generic lambdas added to C++14, you can use the following with a conformant compiler:

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风格的结构typedef在C ++中是不必要的(并且可能在C中的大多数地方不清楚),因此在您拥有的任何地方

Also, C-style struct typedefs are unnecessary in C++ (and arguably unclear most places in C), so anywhere you have

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

您可以将其替换为

struct Foo {
    // ...
};

无需对代码进行任何其他更改.

without any other changes required of your code.

这篇关于无法在具有公共字段的不同类型的结构上应用std :: set_intersection的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆