首页 文章

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

提问于
浏览
6

我正在尝试使用 std::set_intersection 来查找具有共同绑定'name'字段的2种完全不同类型的数据结构之间的公共元素 .

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

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

// 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> C:\ Program Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ algorithm(3591):错误C2664:'bool(__ 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,_Ou tIt,_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>]

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

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实现2个相对简单的结构与公共字段之间的简单绑定?
提前致谢 .

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 Files(x86)\ Microsoft Visual Studio 12.0 \ VC \ include \ xutility(625):请参阅函数参考模板实例化'bool std :: _ Debug_lt_pred <Pr,main :: StructA&,main :: StructA&>( Pr,_Ty1,_Ty2,std :: _ Dbfile_t,std :: _ Dbline_t)'正在编译1> 1> [1> _Pr = main ::比较器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 ::比较器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 ::比较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 ::比较器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':canno t将参数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(625):请参阅函数模板实例化'bool 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 ::比较器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 ::比较器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>没有用户定义的转换运算符可用可以执行此转换,或者无法调用运算符

3 回答

  • -2

    由于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.使用带模板化运算符()的比较器 .

    而不是使用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 {
        // ...
    };
    

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

  • 12

    使用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?

  • 0

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

相关问题