C++ 对左值和右值的可赋值引用

C++ 对左值和右值的可赋值引用,c++,c++11,C++,C++11,假设我有一个函数unique\u count,可以计算任何未排序范围内的唯一元素数: 模板 标准::大小\u t唯一\u计数(先输入,后输入) { 使用T=typename std::iterator\u traits::value\u type; std::向量v(第一个,最后一个); 排序(v.begin(),v.end()); 返回标准::距离(v.begin(), std::unique(v.begin(),v.end()); } 我创建了一个新的向量,因为我不想修改原始容器,但也不想

假设我有一个函数
unique\u count
,可以计算任何未排序范围内的唯一元素数:

模板
标准::大小\u t唯一\u计数(先输入,后输入)
{
使用T=typename std::iterator\u traits::value\u type;
std::向量v(第一个,最后一个);
排序(v.begin(),v.end());
返回标准::距离(v.begin(),
std::unique(v.begin(),v.end());
}
我创建了一个新的
向量
,因为我不想修改原始容器,但也不想进行不必要的复制。最简单的解决方案是生成指针向量,但问题是
*first
可能返回
常量T&
(例如,从
向量
),或
T
(例如,从流)

/**/部分在概念上应等同于
常量T&
。我们不能这样做,因为
vector
s不能保存引用,而引用是不可分配的。我们也不能使用
reference\u wrapper
,因为它不能从临时表构造


我有什么选择?

您想要
/**/
是一种可能拥有或不拥有
T
对象的类型,这取决于它是用临时
T
还是
常量T&
构造的。出于明显的原因,通常应避免此类类型

一种替代方法是使用标记分派或SFINAE从两种可能的实现中选择一种,具体取决于
*first
是返回引用类型还是非引用类型

另一种选择是缩小算法的范围,使其只接受前向迭代器。在这里,您可以保证能够简单地存储迭代器本身,并使用它们来比较指向的元素:

template <typename ForwardIt>
std::size_t unique_count(ForwardIt first, ForwardIt last) {
    std::vector<ForwardIt> v;
    for (auto i = first; i != last; ++i) {
        v.push_back(i);
    }
    const auto pred = [](ForwardIt a, ForwardIt b) { return *a < *b; };
    std::sort(v.begin(), v.end(), pred);
    return std::distance(v.begin(), std::unique(v.begin(), v.end(), pred));
}
模板
std::大小\u t唯一\u计数(先转发,后转发){
std::向量v;
for(自动i=第一;i!=最后;++i){
v、 推回(i);
}
const auto pred=[](ForwardIt a,ForwardIt b){return*a<*b;};
排序(v.begin(),v.end(),pred);
返回std::distance(v.begin(),std::unique(v.begin(),v.end(),pred));
}

您想要
/**/
是一种可能拥有或不拥有
T
对象的类型,这取决于它是用临时
T
还是
常量T&
构造的。出于明显的原因,通常应避免此类类型

一种替代方法是使用标记分派或SFINAE从两种可能的实现中选择一种,具体取决于
*first
是返回引用类型还是非引用类型

另一种选择是缩小算法的范围,使其只接受前向迭代器。在这里,您可以保证能够简单地存储迭代器本身,并使用它们来比较指向的元素:

template <typename ForwardIt>
std::size_t unique_count(ForwardIt first, ForwardIt last) {
    std::vector<ForwardIt> v;
    for (auto i = first; i != last; ++i) {
        v.push_back(i);
    }
    const auto pred = [](ForwardIt a, ForwardIt b) { return *a < *b; };
    std::sort(v.begin(), v.end(), pred);
    return std::distance(v.begin(), std::unique(v.begin(), v.end(), pred));
}
模板
std::大小\u t唯一\u计数(先转发,后转发){
std::向量v;
for(自动i=第一;i!=最后;++i){
v、 推回(i);
}
const auto pred=[](ForwardIt a,ForwardIt b){return*a<*b;};
排序(v.begin(),v.end(),pred);
返回std::distance(v.begin(),std::unique(v.begin(),v.end(),pred));
}

现在我使用
std::conditional
选择
T
reference\u wrapper
之间的向量值类型,具体取决于
is\u lvalue\u reference::value
。你认为这是一个合理的方法吗?@ZizhengTai听起来不错。现在我使用
std::conditional
来选择
T
reference\u wrapper
之间的向量值类型,这取决于
是左值还是reference::value
。你认为这是一个合理的方法吗?@ZizhengTai听起来不错。