C++打印模板容器错误(错误:"运算符<<"的不明确重载)理解?

C++ print template container error (error: ambiguous overload for 'operator<<') understanding?

本文关键字:lt 错误 不明确 重载 理解 打印 C++ 运算符      更新时间:2023-10-16

我想写一个模板函数,它可以打印像std::vector,std::list这样的容器。

下面是我的函数,只过载<<

template<typename Container>
std::ostream& operator<<(std::ostream& out, const Container& c){
for(auto item:c){
out<<item;
}
return out;
}

测试代码如下:

int main(){
std::vector<int> iVec{5, 9, 1, 4, 6};
std::cout<<iVec<<std::endl;
return 0;
}

输出:

59146

我想在每个值中添加一个空格字符串(输出类似于5 9 1 4 6(,所以我将函数更改为:

template<typename Container>
std::ostream& operator<<(std::ostream& out, const Container& c){
for(auto item:c){
out<<item<<" ";
}
return out;
}

然后它得到错误:

merror: ambiguous overload for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'const char [2]')
out<<item<<" ";

我知道<<可以输出类似的常见类型。

int a = 0;
double f = 0.3;
std::string s = "123";
std::cout<<a<<f<<s<<std::endl;

那么为什么会出现上述错误呢?有什么办法解决吗?

我看到了这个问题"operator<lt;'在'std::cout<lt;但我还是听不清楚。

所有代码:

#include <iostream>
#include <vector>
template<typename Container>
std::ostream& operator<<(std::ostream& out, const Container& c){
for(auto item:c){
out<<item;
// out<<item<<" "; // error
}
return out;
}
int main(){
std::vector<int> iVec{5, 9, 1, 4, 6};
std::cout<<iVec<<std::endl;
return 0;
}

声明template<typename Container>可能很危险,因为此模板包括"all"变量类型intchar等。由于此编译器不知道要使用哪个operator<<

为了只获取容器类型变量,请使用模板中的模板。这是的工作代码

template<typename T, template <typename, typename> class Container>
std::ostream& operator<<(std::ostream& out, const Container<T, std::allocator<T>>& c) {
for (auto item : c) {
out << item << " ";
} 
return out;
}
int main()
{
cout << "Hello world" << endl;
int arr[] = { 0,3,6,7 };
vector<int> v(arr, arr+4);
cout << v << endl;
return 0;
}

@miradham很好地解释了这个问题。

但这是一个更通用的解决方案,使用SFINAE使重载只考虑可以使用基于范围的for循环的类型,无论它们的模板参数是什么。

来自std::basic_string的类型被忽略,以防止与显示字符串的标准operator <<产生歧义

c样式数组将不会使用此重载显示,即使它们可以显示,因为它们衰减为指针并使用标准operator <<显示

#include <iostream>
#include <vector>
#include <type_traits>
#include <array>
#include <string>
template<template<typename...> typename From, typename T>
struct is_from : std::false_type {};
template<template<typename...> typename From, typename ... Ts>
struct is_from<From, From<Ts...> > : std::true_type {};
template <typename...>
using void_t = void;
template <typename T, typename = void>
struct is_input_iterator : std::false_type { };
template <typename T>
struct is_input_iterator<T,
void_t<decltype(++std::declval<T&>()),
decltype(*std::declval<T&>()),
decltype(std::declval<T&>() == std::declval<T&>())>>
: std::true_type { };
template<typename Container, 
typename std::enable_if<is_input_iterator<decltype(std::begin(std::declval<Container>()))>::value &&
is_input_iterator<decltype(std::end(std::declval<Container>()))>::value &&
!is_from<std::basic_string, Container>::value, int>::type = 0>
std::ostream& operator<<(std::ostream& out, const Container& c){
for(const auto& item:c){
out << item << " ";
}
return out;
}
int main(){
std::array<int, 6> arr{0, 1, 2, 3, 4, 5};
std::vector<int> vec{5, 9, 1, 4, 6};
std::cout << vec << std::endl;
std::cout << arr << std::endl;
std::cout << std::string("test") << std::endl;
return 0;
}

问题是模板化类型Container可以匹配任何类型,而不仅仅是容器。其中包括您要打印的" "

如果您查看来自其他编译器的错误消息:https://godbolt.org/g/3YKtca

<source>:5:15: note: candidate function [with Container = char [2]]
std::ostream& operator<<(std::ostream& out, const Container& c){

也许您希望vector<T>的部分专门化只取向量。确定一个类型是否是容器是一个更复杂的问题。

#include <iostream>
#include <vector>
template<typename E, typename A>
std::ostream& operator<<(std::ostream& out, const std::vector<E, A>& c){
for(auto item:c){
out<<item;
out<<item<<" "; // error
}
return out;
}
int main(){
std::vector<int> iVec{5, 9, 1, 4, 6};
std::cout<<iVec<<std::endl;
return 0;
}

https://godbolt.org/g/NJNwmN

问题是,您定义的operator<<std::vectorconst char (&array)[N](您试图流式传输到out" "类型(都匹配。

演示问题的简化代码示例:

#include <iostream>
template<typename Container>
std::ostream& operator<<(std::ostream& out, const Container& c)
{
return out;
}
int main()
{
std::cout<<" "<<std::endl;
return 0;
}

以下示例仅将operator<<限制为std::vectors:

template<typename ... Args>
std::ostream& operator<<(std::ostream& out, const std::vector<Args...>& c)
{
for(auto item:c){
out<<item<<" ";
}
return out;
}

活生生的例子。