4

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

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_sameand的事情std::is_base_of,当前者不起作用时,只是为了最终意识到这是没有意义的,因为任何继承自的参数类型std::basic_ostream<>都将被转换为我在传递给函数时与之比较的类型,从而产生误报。

这最终使我得到了下面的答案(可变参数模板模板参数?哇,真是一口!)但是有几个问题:

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

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

4

2 回答 2

1

这是我经过大量试验后得出的结论:

template<template<typename...> class T, typename... U>
void foo(T<U...> &os) {
    static_assert(
        std::is_same<
            std::basic_ostream<U...>, 
            typename std::remove_reference<decltype(os)>::type
        >::value, 
        "Argument must be of type std::basic_ostream<T, U>."
    );
    //...
}

可以在此处找到包含以下每个测试的源代码。可以在此处
找到将类型替换为更明确并提供更多自由(例如,实例化)的类似自制类型的源代码,这可能对测试更有用。

  • 传入std::coutstd::wcout使其编译正常。
  • 传入一个实例std::ostringstream会导致它抱怨模板参数的数量。
  • 传入std::fstream具有相同数量模板参数的 实例会导致静态断言失败。
  • 传入自制的 2 参数模板类会导致静态断言失败。

请随时以任何方式对此进行改进。

于 2012-11-01T07:19:39.490 回答
1

这是检测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和将允许在支持可变模板参数的编译器上编写通用特征。Vis_instantiation_of


要检测 stdout 是否通过管道传输到文件(当然只能在运行时检测到),请使用isatty; 看看如何在 cout 上使用 isatty(),或者我可以假设 cout == 文件描述符 1?

于 2012-11-01T09:21:00.640 回答