C ++打印模板容器错误(错误:“ operator <<”的模棱两可的重载)理解了吗?

时间:2018-07-26 05:20:35

标签: c++ c++11

我想编写模板函数,该函数可以打印<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;

4 个答案:

答案 0 :(得分:4)

声明template<typename Container>可能很危险,因为此模板包含“所有”变量类型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;
}

答案 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;
}

https://godbolt.org/g/NJNwmN

答案 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::vectorconst 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

Live example