【发布时间】:2014-04-18 16:25:47
【问题描述】:
我需要对 std::set_intersection 做一些奇怪的事情,但我无法弄清楚。大约一个月前我问了一个类似的question,由于对这个问题的出色回答,我解决了使 std::set_intersection 使用 2 个向量之间的公共链接字段工作的问题,每个向量包含不同类型的对象.
我现在面临的问题是我试图让下面的代码工作,我基本上需要将 std::set_intersection 的输出写入一个新类型,它实际上是 StructA 中的一些字段和其他字段之间的联合来自 StructB。我使用了用户tclamb 编写的稍作修改的示例,但它没有编译,我对编译器错误有点迷失。我很确定我面临的一些问题与限制有关
根据std::set_intersection InputIterator1 和 InputIterator2 中的类型要求部分具有相同的值类型。在我的情况下,这不是真的,在 tclamb 解决方案的情况下也不是这样,但它似乎有效。
我刚刚编辑了下面的代码,并结合了@ivar 对一些冗余代码的建议——这使问题更容易阅读——它现在正在编译和运行——但仍然产生了我想要的结果。实时代码也发布在coliru
#include<vector>
#include<algorithm>
#include<string>
#include <iostream>
#include <iterator>
// I wish to return a vector of these as the result
struct StructC {
std::string mCommonField;
std::string mNameFromA; // cherry picked from StructA
std::string mNameFromB; // cherry picked from StructB
float mFloatFromA; // cherry picked from StructA
int mIntFromB; // cherry picked from StructB
};
struct StructA {
// conversion operator from StructA to StructC
operator StructC() { return { mCommonField, mNameAString, "[]", mFloatValueA, 0 }; }
std::string mCommonField;
std::string mNameAString;
float mFloatValueA;
};
struct StructB {
// conversion operator from StructB to StructC
operator StructC() { return { mCommonField, "[]", mNameBString, 0.0f, mIntValueB }; }
std::string mCommonField;
std::string mNameBString;
int mIntValueB;
};
// Comparator thanks to @ivar
struct Comparator {
template<typename A, typename B>
bool operator()(const A& a, const B& b) const {
return a.mCommonField < b.mCommonField;
}
};
template<typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, StructC const& sc) {
return os << sc.mCommonField << " - " << sc.mNameFromA << " - "
<< sc.mNameFromB << " - " << std::fixed << sc.mFloatFromA << " - " << sc.mIntFromB << std::endl;
}
int main() {
Comparator comparator;
// initially unsorted list of StructA
std::vector<StructA> aStructs = {
{"hello", "nameA1", 1.0f},
{"goodbye", "nameA2", 2.0f},
{"foo", "nameA3", 3.0f}
};
// initially unsorted list of StructB
std::vector<StructB> bStructs = {
{"hello", "nameB1", 10}, // <-- intersection as mCommonField("hello") also in aStructs
{"goodbye", "nameB2", 20}, // <-- intersection as mCommonField("goodbye") also in aStructs
{"bar", "nameB3", 30}
};
// in the above list, "hello" & "goodbye" are the common in both aStructs & bStructs
// pre-sort both sets before calling std::intersection
std::sort(aStructs.begin(), aStructs.end(), comparator);
std::sort(bStructs.begin(), bStructs.end(), comparator);
std::vector<StructC> intersection;
std::set_intersection(aStructs.begin(), aStructs.end(),
bStructs.begin(), bStructs.end(),
std::back_inserter(intersection),
comparator);
std::copy(intersection.begin(), intersection.end(),
std::ostream_iterator<StructC>(std::cout, ""));
return 0;
}
【问题讨论】:
-
将
A和B作为输入参数添加到C两个复制/移动构造函数。我认为这应该足够了。 -
帮自己一个忙,不要再看 SGI STL 文档了:C++ 标准库实际上是在 20 年前从 STL 派生出来的,从那时起事情就发生了分歧。例如,cppreference.com page for
std::set_intersection没有列出两种输入迭代器类型需要具有相同值类型的要求——因为 C++ 标准不要求它们这样做。 -
谢谢,这是个好建议,它表明“类型 Type1 和 Type2 必须使得 InputIt1 和 InputIt2 类型的对象可以被取消引用,然后分别隐式转换为 Type1 和 Type2。”
-
@iavr 你能给我一个简单的例子来说明你的意思吗?我将我的代码更改为 StructA 和 StructB 的 C 转换运算符 - 这不是等效的,即使如此它仍然不足以满足我的需求。如果 StructA 和 StructB 不是我的结构并因此不可修改,我会认为这是一件有用的事情。
-
@johnco3 看我的回答。
标签: c++ c++11 stl stl-algorithm