范围并不像人们所希望的那样神奇。最后,必须有一个对象,编译器可以生成对成员函数或自由函数begin()
和end()
的调用。
您可能最能接近的是:
#include <iostream>
int main()
{
int a{},b{},c{},d{};
for (auto s : {&a,&b,&c,&d} ) {
*s = 1;
}
std::cout << a << "\n";
return 0;
}
,
根据标准§11.6.4List-initialization / p5 [dcl.init.list] [重点矿山]:
“ std :: initializer_list”类型的对象是通过
初始化程序列表,好像实现已生成并实现
(7.4)类型为“ N const E的数组” 的prvalue,其中N是
初始化列表中的元素。该数组的每个元素是
使用初始化程序的相应元素进行复制初始化
列表,并且构造了std :: initializer_list对象以引用
到那个数组。 [注意:已选择构造函数或转换函数
在以下情况下,该副本应可访问(第14条)
初始化列表。 —尾注]如果需要缩小转换
要初始化任何元素,程序的格式是错误的。
因此,您的编译器在进行正当的抱怨(即auto &s
扣除到int const& s
,并且您不能在范围for循环中分配给s
)。
您可以通过引入容器而不是带有“ std :: reference_wrapper”的初始化列表(例如“ std :: vector”)来缓解此问题:
#include <iostream>
#include <vector>
#include <functional>
int main()
{
int a{},d{};
for (auto& s : std::vector<std::reference_wrapper<int>>{a,b,c,d}) {
s.get()= 1;
}
std::cout << a << std::endl;
return 0;
}
Live Demo
,
包装方法中的另一个解决方案:
template<typename T,std::size_t size>
class Ref_array {
using Array = std::array<T*,size>;
class Iterator {
public:
explicit Iterator(typename Array::iterator it) : it_(it) {}
void operator++() { ++it_; }
bool operator!=(const Iterator& other) const { return it_ != other.it_; }
decltype(auto) operator*() const { return **it_; }
private:
typename Array::iterator it_;
};
public:
explicit Ref_array(Array args) : args_(args) {}
auto begin() { return Iterator(args_.begin()); }
auto end() { return Iterator(args_.end()); }
private:
Array args_;
};
template<typename T,typename... Ts>
auto something(T& first,Ts&... rest) {
static_assert((std::is_same_v<T,Ts> && ...));
return Ref_array<T,1 + sizeof...(Ts)>({&first,&rest...});
}
然后:
int main() {
int a{},d{};
for (auto& s : something(a,d)) {
std::cout << s;
s = 1;
}
std::cout << std::endl;
for (auto& s : something(a,d))
std::cout << s;
}
输出
0000
1111
,
要满足该语法
for (auto& s : something{a,d}) {
s = 1;
}
您可以创建包装器:
template <typename T>
struct MyRefWrapper
{
public:
MyRefWrapper(T& p) : p(&p) {}
T& operator =(const T& value) const { return *p = value; }
operator T& () const { return *p; }
private:
T* p;
};
Demo
,
解决方案:使用参考包装器
template <class It>
struct range_view_iterator : public It{//TODO: don't inherit It
auto& operator*() {
return (*this)->get();
}
};
template<class It>
range_view_iterator(It) -> range_view_iterator<It>;
template<class T>
struct range_view {
std::vector<std::reference_wrapper<T> > refs_;
range_view(std::initializer_list<std::reference_wrapper<T> > refs) : refs_{refs} {
}
auto begin() {
return range_view_iterator{ refs_.begin() };
}
auto end() {
return range_view_iterator{ refs_.end() };
}
};
然后用作:
for (auto& e : range_view<int>{a,d}) {
e = 1;
}
这不会尝试回答第一个问题。
,
您可以创建包装类来存储引用,并且包装类将具有赋值运算符来更新此值:
template<class T>
struct Wrapper {
T& ref;
Wrapper(T& ref)
: ref(ref){}
template<class U>
void operator=(U u) {
ref = u;
}
};
template<class...T>
auto sth(T&...t) {
return std::array< Wrapper<std::common_type_t<T...> >,sizeof...(t) >{Wrapper(t)...};
};
int main(){
int a{},d{};
for (auto s : sth(a,d)) {
s = 1;
}
std::cout << a << std::endl; // 1
Live demo
本文链接:https://www.f2er.com/3152130.html