C++ 将范围与std::set一起使用

C++ 将范围与std::set一起使用,c++,c++11,C++,C++11,我想用几个数字范围初始化std::set。我希望能够高效地完成这项工作(最少的复制),而无需使用boost,并且目前对最终用户(我自己:)具有良好的代码可读性) 以下是我到目前为止提出的,但我可以看到一些效率低下的问题,并希望得到关于是否可行以及如何解决这些问题的建议。具体问题在代码下面 #include <iostream> #include <set> typedef std::set<int> codes; template<typename

我想用几个数字范围初始化
std::set
。我希望能够高效地完成这项工作(最少的复制),而无需使用
boost
,并且目前对最终用户(我自己:)具有良好的代码可读性)

以下是我到目前为止提出的,但我可以看到一些效率低下的问题,并希望得到关于是否可行以及如何解决这些问题的建议。具体问题在代码下面

#include <iostream>
#include <set>

typedef std::set<int> codes;

template<typename T>
inline codes operator|(codes&& x, T&& y)
{
    codes c(std::move(x));
    c.insert(y.begin(), y.end());
    return c;
}

template<typename T>
inline codes operator|(const codes& x, T&& y)
{
    codes c(std::forward<T>(y));
    c.insert(x.begin(), x.end());
    return c;
}

inline codes range(int min, int max)
{
    codes c;
    for(int ri = min; ri < max; ++ri) c.insert(ri);
    return c;
}

void print_set(const std::string& name, const codes& set)
{
    std::cout << name << " = ";
    for(int ri: set) std::cout << ri << ' ';
    std::cout << std::endl;
}

int main()
{
    codes r1 = { 1, 2, 3 };
    codes r2 = range(5, 10);
    codes r3 = r1 | r2;
    codes r4 = r2 | range(15, 20);
    codes r5 = range(1, 10) | r1;
    codes r6 = range(1, 5) | range(10, 15);

    print_set("r1", r1);
    print_set("r2", r2);
    print_set("r3", r3);
    print_set("r4", r4);
    print_set("r5", r5);
    print_set("r6", r6);

    return 0;
}
#包括
#包括
typedef std::设置代码;
模板
内联代码运算符|(代码和x、T和y)
{
代码c(std::move(x));
c、 插入(y.开始(),y.结束());
返回c;
}
模板
内联代码运算符|(常量代码&x,T和&y)
{
代码c(std::forward(y));
c、 插入(x.begin(),x.end());
返回c;
}
内联代码范围(最小整数、最大整数)
{
代码c;
对于(int ri=min;ri
template<typename T>
inline codes operator|(codes&& x, T&& y)
{
    codes c(std::move(x));
    c.insert(y.begin(), y.end());
    return c;
}

template<typename T>
inline codes operator|(const codes& x, T&& y)
{
    codes c(std::forward<T>(y));
    c.insert(x.begin(), x.end());
    return c;
}
模板
内联代码运算符|(代码和x、T和y)
{
代码c(std::move(x));
c、 插入(y.开始(),y.结束());
返回c;
}
模板
内联代码运算符|(常量代码&x,T和&y)
{
代码c(std::forward(y));
c、 插入(x.begin(),x.end());
返回c;
}
可以写成:

template<typename T>
inline codes operator|(codes x, T&& y)
{
    using std::begin;
    using std::end;
    x.insert( begin(y), end(y) );
    return x;
}
模板
内联代码运算符|(代码x、T和y)
{
使用std::begin;
使用std::end;
x、 插入(开始(y),结束(y));
返回x;
}
通过值传递
codes x
将为左值和右值实现正确且经过良好测试的
std::set
构造函数。

所有这些:

template<typename T>
inline codes operator|(codes&& x, T&& y)
{
    codes c(std::move(x));
    c.insert(y.begin(), y.end());
    return c;
}

template<typename T>
inline codes operator|(const codes& x, T&& y)
{
    codes c(std::forward<T>(y));
    c.insert(x.begin(), x.end());
    return c;
}
模板
内联代码运算符|(代码和x、T和y)
{
代码c(std::move(x));
c、 插入(y.开始(),y.结束());
返回c;
}
模板
内联代码运算符|(常量代码&x,T和&y)
{
代码c(std::forward(y));
c、 插入(x.begin(),x.end());
返回c;
}
可以写成:

template<typename T>
inline codes operator|(codes x, T&& y)
{
    using std::begin;
    using std::end;
    x.insert( begin(y), end(y) );
    return x;
}
模板
内联代码运算符|(代码x、T和y)
{
使用std::begin;
使用std::end;
x、 插入(开始(y),结束(y));
返回x;
}

通过值传递
代码x
将为左值和右值实现正确且经过良好测试的
std::set
构造函数。

代码r3=r1 | r2;代码r4=r2 |范围(15,20);假设r2没有被复制而是被移动,那么您的第二条语句将变得无效,对吗?@Jagannath,
r2
是一个l值,所以它不会被移动。
range(15,20)
另一边应该移动。这就是为什么我有几个版本的
操作符
来处理各种情况。显然,有些情况下无法避免复制。我认为除了模板专门化之外,我们不能将自己的东西放入
std
命名空间,不是吗?”
操作符(&&x,&&y)
version仍然必须从
y
复制元素。是否可以避免它?”-您可以将范围存储为构建合并逻辑的
std::set
,以保持最小的非重叠范围集,然后仅在绝对必要时对其进行扩展。(我以前在2D中这样做是为了在巨大的网格小部件中跟踪单元格选择。)@NickyC,你是对的。我调整了问题代码r3=r1 | r2;代码r4=r2 |范围(15,20);假设r2没有被复制而是被移动,那么您的第二条语句将变得无效,对吗?@Jagannath,
r2
是一个l值,所以它不会被移动。
range(15,20)
另一边应该移动。这就是为什么我有几个版本的
操作符
来处理各种情况。显然,有些情况下无法避免复制。我认为除了模板专门化之外,我们不能将自己的东西放入
std
命名空间,不是吗?”
操作符(&&x,&&y)
version仍然必须从
y
复制元素。是否可以避免它?”-您可以将范围存储为构建合并逻辑的
std::set
,以保持最小的非重叠范围集,然后仅在绝对必要时对其进行扩展。(我以前在2D中这样做是为了在巨大的网格小部件中跟踪单元格选择。)@NickyC,你是对的。我调整了问题Drew,很好的一个。
+1
为你准备的先生。Drew,为什么
std::begin(y)
而不是
y.begin()
?@InnocentBystander这更为惯用。@NickyC,请elaborate@InnocentBystander像C数组
int[3]
这样的类型不会有
begin
成员函数。但它在这里可以工作。Drew,很好的一个。
+1
适合你,先生。Drew,为什么
std::begin(y)
而不是
y.begin()
?@InnocentBystander这更为惯用。@NickyC,请elaborate@InnocentBystander像C数组
int[3]
这样的类型不会有
begin
成员函数,但在这里可以工作。