如何编写流媒体';操作员<<';可以容纳任意容器(类型为';X';)? < >我有一个C++类“ x>代码>,如果容器的被发送到 STD::OSWATE ,这将具有特殊意义。

如何编写流媒体';操作员<<';可以容纳任意容器(类型为';X';)? < >我有一个C++类“ x>代码>,如果容器的被发送到 STD::OSWATE ,这将具有特殊意义。,c++,templates,stl,iostream,C++,Templates,Stl,Iostream,我最初专门为std::vector实现它: std::ostream&operator模板 std::ostream&operataor如果您以前阅读过此答案,您可能希望向下滚动到下面的ADL版本。改进了很多 首先,这是一个非常有效的简短版本: #include <iostream> #include <type_traits> template<typename T, typename Iterator, typename=void> struct is_i

我最初专门为
std::vector
实现它:

std::ostream&operator
模板

std::ostream&operataor如果您以前阅读过此答案,您可能希望向下滚动到下面的ADL版本。改进了很多

首先,这是一个非常有效的简短版本:

#include <iostream>
#include <type_traits>
template<typename T, typename Iterator, typename=void>
struct is_iterator_of_type: std::false_type {};

template<typename T, typename Iterator>
struct is_iterator_of_type<
  T,
  Iterator,
  typename std::enable_if<
    std::is_same<
      T,
      typename std::iterator_traits< Iterator >::value_type
    >::value
  >::type
>: std::true_type {};

template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
  typename std::enable_if< is_iterator_of_type<int, typename Container::iterator>::value, std::ostream& >::type
{
  return stream << "int container\n";
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
  typename std::enable_if< is_iterator_of_type<double, typename Container::iterator>::value, std::ostream& >::type
{
  return stream << "double container\n";
}
这样一来,
double
s数组不仅可以算作
double
上的容器,而且在它的命名空间中定义了一个
begin
end
函数,该函数返回以容器为参数的double上的迭代器也可以工作。这与
for(auto&&i:container)
查找的工作方式相匹配(完美?相当好?),因此“container”的良好工作定义也是如此

然而,请注意,随着我们添加更多这些修饰,拥有我们正在使用的所有C++11特性的当前编译器越来越少。我相信以上是在GCC4.6中编译的,但不是GCC4.5.*

下面是原始的简短代码,其中包含一些测试框架:(如果编译器抛出它,您可以在下面看到哪里出错,这很有用)

#包括
#包括
#包括
#包括
#包括
模板
结构是类型为std::false\u类型{}的迭代器;
模板
结构是类型为的迭代器<
T
迭代器,
typename std::启用\u如果<
std::是一样的吗<
T
typename std::iterator\u traits::value\u type
>::价值
>::类型
>:std::true_type{};
void test1(){
std::cout::type
{

std::cout简单但不优雅-下一个维护代码的人可能会喜欢缺少花哨的模板!实际上,我会将“Print”方法隐藏在cpp中,或者至少是一个
Detail
名称空间中

#include <iostream>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <multiset>

class X {};

template <typename T>
std::ostream& Print(std::ostream& os, const T& container)
{
    for(auto ii = container.cbegin(); ii != container.cend(); ++ii);
        //etc
        //
    return os;
}

std::ostream& operator<<(std::ostream& os, const std::vector<X>& v) { return Print(os, v); }
std::ostream& operator<<(std::ostream& os, const std::deque<X>& v) { return Print(os, v); }
std::ostream& operator<<(std::ostream& os, const std::list<X>& v) { return Print(os, v); }
std::ostream& operator<<(std::ostream& os, const std::set<X>& v) { return Print(os, v); }
std::ostream& operator<<(std::ostream& os, const std::multiset<X>& v) { return Print(os, v); }

int main()
{
            // Example
    std::vector<X> v;
    std::cout << v;
}
#包括
#包括
#包括
#包括
#包括
#包括
类X{};
模板
std::ostream&Print(std::ostream&os、const T&container)
{
for(auto ii=container.cbegin();ii!=container.cend();++ii);
//等
//
返回操作系统;
}

std::ostream&operator如果您稍微将问题重新定义为为为任何提供基于范围的小部件访问的类提供特殊流行为,而不是为所有小部件容器提供特殊行为,那么一个解决方案是:

  template <class Container>
  std::ostream& operator << (std::ostream &out, const Container &container) 
  {
    for(const Widget& c : container) {
      out << c;
      out.put(' ');
    }
    return out;
  }
模板

std::ostream&operator虽然@razeh有一个很好的解决方案,但如果您需要对
X
容器和
Y
容器进行专门的打印,您可以执行以下操作:

    // Types for which you want specialized streaming of containers
    // We need some identifiable typedef in these types
    struct  X { typedef void X_type; };
    struct  Y { typedef void Y_type; };


    // Wrappers for implementing streaming logic for each type        

template <typename C>
struct WrapX
{
    WrapX(const C& c) : c(c) { }
    const C& c;

    std::ostream& stream(std::ostream& os)
    {
         // Special container of X printing
         return os;
    }
};

template <typename C>
struct WrapY
{
    WrapY(const C& c) : c(c) { }
    const C& c;

    std::ostream& stream(std::ostream& os)
    {
        // Special container of Y printing
        return os;
    }
};

    // Wrap functions, by using a 'dummy' parameter
    // we can get the compiler to select the function based
    // on the incoming type

template <typename C >
WrapX<C> Wrap(const C& c,  typename C::value_type::X_type* = 0) { return WrapX<C>(c); }

template <typename C>
WrapY<C> Wrap(const C& c, typename C::value_type::Y_type* = 0) { return WrapY<C>(c); }



    // Overload - same problem as @razeh solution, this is a VERY generic
    // function and may clash with other declarations. Keep it closely confined to
    // where you need it.
template <typename C>
std::ostream& operator<<(std::ostream& os, const C& c) { return Wrap(c).stream(os);  }




int main()
{
    std::vector<X> vx;
    std::cout << vx;

        std::vector<Y> vy;
        std::cout << vy;
}
//要对其进行专门的容器流式处理的类型
//在这些类型中,我们需要一些可识别的typedef
结构X{typedef void X_type;};
结构Y{typedef void Y_type;};
//为每种类型实现流逻辑的包装器
模板
结构WrapX
{
WrapX(常数C&C):C(C){}
康斯特C&C;
标准::ostream和stream(标准::ostream和os)
{
//X打印专用容器
返回操作系统;
}
};
模板
结构WrapY
{
WrapY(常数C&C):C(C){}
康斯特C&C;
标准::ostream和stream(标准::ostream和os)
{
//Y型印刷专用容器
返回操作系统;
}
};
//使用“dummy”参数包装函数
//我们可以让编译器选择基于
//关于传入类型
模板
WrapX Wrap(const C&C,typename C::value_type::X_type*=0){return WrapX(C);}
模板
WrapY Wrap(常量C&C,类型名C::value_type::Y_type*=0){返回WrapY(C);}
//重载-与@razeh解决方案相同的问题,这是一个非常通用的解决方案
//函数,并可能与其他声明冲突。请将其严格限制在
//在你需要的地方。
模板

std::ostream&operatorI会用一个模板来回答这个问题,该模板只会在容器上循环依次打印每个项目,但是您写道“操作将比单独发送每个X更复杂”我认为这需要更多的解释你到底想要它做什么?只是重载
operator会对@J99的第一个问题感兴趣。你能给我们展示一下
operator的实现吗?一个非常简单的解决方案是使用
ostream实际上有一个相当简单的方法来实现“X的容器上的重载”工作,我基本上已经完成了,但我仍在尝试一些东西,我在答案草稿中保存的解释消失了,所以是的……也许今晚晚些时候。这对
vector
deque
list
有效,但对其他所有东西都无效。假设任何类型都有两个模板参数
X,STD::分配器< /代码>将是一个容器,用于<代码> x <代码>?在代码中用<代码> const容器和替换“代码<容器/<代码>,这看起来是显而易见的解决方案……这听起来像是一个合理的重新定义问题。我认为它会引起比您提到的错误更多,因为该函数将被考虑。例如,在一个项目中不能有两个。const&是个好主意,我对代码进行了编辑以匹配。Drew说得对,一个项目中不能有两个以上的容器。这既简单又优雅。有没有办法将此应用于不在其中的容器C++03库?甚至是我还不知道的库?只需添加更多重载。例如
std::ostream&operator我认为这些都是相当可靠的解决方案,尽管它们没有回答这个问题。我同意如果我放弃让它为
X
的任意容器工作,或者如果我放弃实现“
运算符流式代码已经编写。我正在寻找一种方法来为所有容器类型声明它。此解决方案不起作用,但是
#include <iostream>
#include <type_traits>
#include <vector>
#include <iostream>
#include <set>

template<typename T, typename Iterator, typename=void>
struct is_iterator_of_type: std::false_type {};

template<typename T, typename Iterator>
struct is_iterator_of_type<
  T,
  Iterator,
  typename std::enable_if<
    std::is_same<
      T,
      typename std::iterator_traits< Iterator >::value_type
    >::value
  >::type
>: std::true_type {};

void test1() {
  std::cout << is_iterator_of_type<int, std::vector<int>::iterator>::value << "\n";
}
template<typename T, typename Container>
auto foo(Container const&) -> typename std::enable_if< is_iterator_of_type<T, typename Container::iterator>::value >::type
{
  std::cout << "Container of int\n";
}
template<typename T>
void foo(...)
{
  std::cout << "No match\n";
}
void test2() {
  std::vector<int> test;
  foo<int>(test);
  foo<int>(test.begin());
  foo<int>(std::set<int>());
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
  typename std::enable_if< is_iterator_of_type<int, typename Container::iterator>::value, std::ostream& >::type
{
  return stream << "int container\n";
}
void test3() {
  std::vector<int> test;
  std::cout << test;
  std::set<int> bar;
  std::cout << bar;
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
  typename std::enable_if< is_iterator_of_type<double, typename Container::iterator>::value, std::ostream& >::type
{
  return stream << "double container\n";
}
void test4() {
  std::vector<int> test;
  std::cout << test;
  std::set<int> bar;
  std::cout << bar;
  std::vector<double> dtest;
  std::cout << dtest;
}
void test5() {
  std::vector<bool> test;
  // does not compile (naturally):
  // std::cout << test;
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
  typename std::enable_if< is_iterator_of_type<bool, typename Container::iterator>::value, std::ostream& >::type
{
  return stream << "bool container\n";
}
void test6() {
  std::vector<bool> test;
  // now compiles:
  std::cout << test;
}
int main() {
  test1();
  test2();
  test3();
  test4();
  test5();
  test6();
}
#include <iostream>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <multiset>

class X {};

template <typename T>
std::ostream& Print(std::ostream& os, const T& container)
{
    for(auto ii = container.cbegin(); ii != container.cend(); ++ii);
        //etc
        //
    return os;
}

std::ostream& operator<<(std::ostream& os, const std::vector<X>& v) { return Print(os, v); }
std::ostream& operator<<(std::ostream& os, const std::deque<X>& v) { return Print(os, v); }
std::ostream& operator<<(std::ostream& os, const std::list<X>& v) { return Print(os, v); }
std::ostream& operator<<(std::ostream& os, const std::set<X>& v) { return Print(os, v); }
std::ostream& operator<<(std::ostream& os, const std::multiset<X>& v) { return Print(os, v); }

int main()
{
            // Example
    std::vector<X> v;
    std::cout << v;
}
  template <class Container>
  std::ostream& operator << (std::ostream &out, const Container &container) 
  {
    for(const Widget& c : container) {
      out << c;
      out.put(' ');
    }
    return out;
  }
    // Types for which you want specialized streaming of containers
    // We need some identifiable typedef in these types
    struct  X { typedef void X_type; };
    struct  Y { typedef void Y_type; };


    // Wrappers for implementing streaming logic for each type        

template <typename C>
struct WrapX
{
    WrapX(const C& c) : c(c) { }
    const C& c;

    std::ostream& stream(std::ostream& os)
    {
         // Special container of X printing
         return os;
    }
};

template <typename C>
struct WrapY
{
    WrapY(const C& c) : c(c) { }
    const C& c;

    std::ostream& stream(std::ostream& os)
    {
        // Special container of Y printing
        return os;
    }
};

    // Wrap functions, by using a 'dummy' parameter
    // we can get the compiler to select the function based
    // on the incoming type

template <typename C >
WrapX<C> Wrap(const C& c,  typename C::value_type::X_type* = 0) { return WrapX<C>(c); }

template <typename C>
WrapY<C> Wrap(const C& c, typename C::value_type::Y_type* = 0) { return WrapY<C>(c); }



    // Overload - same problem as @razeh solution, this is a VERY generic
    // function and may clash with other declarations. Keep it closely confined to
    // where you need it.
template <typename C>
std::ostream& operator<<(std::ostream& os, const C& c) { return Wrap(c).stream(os);  }




int main()
{
    std::vector<X> vx;
    std::cout << vx;

        std::vector<Y> vy;
        std::cout << vy;
}