错误:使用通用引用的声明冲突

error: conflicting declaration using universal references

本文关键字:声明 冲突 引用 错误      更新时间:2023-10-16

我想从文章中实现通用反向函数,它适用于右值。但没有左值。

#include <iostream>
#include <vector>
#include <functional>
template <typename T>
class Reverse
{
T iterable_;  
public:
explicit Reverse(T&& iterable) : iterable_(std::forward<T>(iterable)){}
auto begin() { return std::rbegin(iterable_); }
auto end() { return std::rend(iterable_); }
};
std::vector<int> CreateVector()
{
return {0,1,2,3,4,5,6,7,8,9};
}
int main()
{
std::vector<int> v{1,2,3,4,5,6,7};   // line 23
for(const auto& i : Reverse(CreateVector()))
std::cout << i << " "; 
std::cout << std::endl;
Reverse(v);                          // line 29
// for(const auto& i : Reverse(v))
//   std::cout << i << " "; 
return 0;    
}

我收到左值的错误:

main.cpp: In function 'int main()':
main.cpp:29:13: error: conflicting declaration 'Reverse<...auto...> v'
29 |     Reverse(v);
|             ^
main.cpp:23:22: note: previous declaration as 'std::vector<int> v'
23 |     std::vector<int> v{1,2,3,4,5,6,7};
| 

你能告诉我一个正确解决方案的方向吗?

首先,您不使用通用/转发引用,而只使用纯 R 值引用。

您需要语法template<class T> F(T&&)(构造函数必须是模板函数(:

template<class F>
explicit Reverse(F&& iterable) : iterable_(std::forward<T>(iterable)){}

如果您使用的是 C++17 或更高版本,则可以添加扣除指南:

template<class T>
Reverse(T&&) -> Reverse<T>;

通过上面添加,您在设置类对象时不必显式指定Reverse类的模板参数。如果没有 CTAD,您需要编写:Reverse<decltype(v)>(..)来处理 R 值,或Reverse<decltype((v))>L 值(需要大多数内部括号才能获取容器的 L 值引用(。

如果你想创建临时Reversev作为参数,只需写:

Reverse{v};

(现在Reverse(v)您重新声明v变量(或作为命名实例:

Reverse withLvalue(v);

演示

如果您启用警告,您将获得该错误的非常重要的线索:

warning: unnecessary parentheses in declaration of 'v' [-Wparentheses]
46 |     Reverse(v)

从编译器的角度来看,v是对象的名称(参数将被忽略(。由于名为v的对象已存在,因此必须选择其他名称。

尽可能首选统一初始化。它不会留下模棱两可的空间。

Reverse{v};

您将遇到的下一个问题是您正在尝试将 l 值(向量v(绑定到构造函数中的 r 值引用Reference。如果要保留该构造函数,则必须将向量移动到此对象中。

Reverse{std::move(v)};

请注意,此操作后v将保留empty()。数据现在仅由iterable_持有。


最后,Reverse对象是临时的,在构造后立即丢弃。您可能希望给它起一些名称,以便稍后在循环中使用它(或者像在第一个循环中那样就地构造临时(。

Reverse myReverse {std::move(v)};
for(const auto& i : myReverse )
std::cout << i << " "; 
//or
for(const auto& i : Reverse{std::move(v)} )
std::cout << i << " ";