c – 确保参数是控制台的输出流

我正在尝试制作一个颜色的流操纵器,用于输出到控制台.它工作,改变文本和背景的颜色:

std::cout << ConColor::Color::FgBlue << 123 << "abc"; //text is blue, sticky

问题在于签名:

std::ostream &FgBlue(std::ostream &);

此签名允许派生类,例如std :: ostringstream,但是无法更改字符串流的颜色.无论是否使用这样的参数调用,该函数都会改变控制台的颜色.

因此,我想确保参数是std :: cout,std :: wcout等等.我希望在将来的标准中添加更多std :: ostream对象时,它是通用的.

我尝试了许多涉及std :: is_same和std :: is_base_of的事情,当前者不起作用时,只是为了最终意识到它没有意义,因为任何参数类型都继承自std :: basic_ostream<>当传递给函数时,将被转换为我正在比较的类型,给出误报.

这最终导致我在下面的回答(可变参数模板模板参数?哇,这是一个满口的!)然而,有几个问题:

>编译器必须支持可变参数模板.我更希望解决方案适用于MSVC.
>如果使用具有不同数量的模板参数的派生类(例如std :: ostringstream,其中有3而不是2),编译器会给出神秘错误,因为它没有通过函数签名.
>例如,可以将stdout重定向到文件,因此即使参数是std :: cout,也会发生与stringstream情况相同的事情.

我鼓励人们发布任何其他解决方案,希望比我的更好,并且真的希望至少与VS11一起使用.

最佳答案 这是检测std :: basic_ostream实例化的特性:

template<typename T> struct is_basic_ostream {
  template<typename U, typename V>
  static char (&impl(std::basic_ostream<U, V> *))[
    std::is_same<T, std::basic_ostream<U, V>>::value ? 2 : 1];
  static char impl(...);
  static constexpr bool value = sizeof(impl((T *)0)) == 2;
};

用于:

template<typename T>
void foo(T &) {
  static_assert(is_basic_ostream<T>::value,
    "Argument must be of type std::basic_ostream<T, U>.");
}

我们使用模板参数推导来推断(非正确的)basic_ostream基类上的模板参数(如果有的话).作为一种更通用的解决方案,用单个可变参数替换U和V将允许在支持可变参数模板参数的编译器上编写通用的is_instantiation_of特性.

要检测stdout是否通过管道传输到文件(当然只能在运行时检测到),请使用isatty;见how to use isatty() on cout, or can I assume that cout == file descriptor 1?

点赞