我想编写模板函数,该函数可以打印<div class="A">
<div class="First-Para">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Esse, natus <b style="color: red">*</b></p>
</div>
</div>
,std :: list之类的容器。
下面是我的函数,只是重载std::vector
。
<<
测试代码如下:
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<<" ";
可以输出类似的普通类型。
<<
那么为什么会出现上述错误?有什么办法解决吗?
我看到了这个问题Ambiguous overload for ‘operator<<’ in ‘std::cout <<,但我仍然不清楚。
所有代码:
int a = 0;
double f = 0.3;
std::string s = "123";
std::cout<<a<<f<<s<<std::endl;
答案 0 :(得分:4)
声明template<typename Container>
可能很危险,因为此模板包含“所有”变量类型int
,char
等。由于此编译器不知道要使用哪个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;
}
答案 1 :(得分:3)
问题在于模板化类型的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;
}
答案 2 :(得分:3)
@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;
}
答案 3 :(得分:1)
问题是您定义的operator<<
与std::vector
和const char (&array)[N]
都匹配(您尝试流式传输到" "
的{{1}}的类型)
一个简单的代码示例演示了这个问题:
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::vector