我正在尝试为颜色制作一个流操纵器,以便与输出到控制台一起使用。它有效,改变了文字和背景的颜色:
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<>
的任何参数类型都将被转换传递给函数时我正在比较的类型,给出误报。
这最终导致我在下面给出了我的答案(可变参数模板模板参数?哇,这是一个满口!)但是有几个问题:
std::ostringstream
,其中有3而不是2)的情况下给出了神秘错误,因为它没有通过该函数签名。std::cout
,也会发生与stringstream情况相同的事情。我鼓励人们发布任何其他解决方案,希望比我更好,并且真的希望至少能与VS11一起使用。
答案 0 :(得分: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>."
);
//...
}
可以找到包含以下每项测试的源代码here 可以找到源代码替换具有类似的自制类型的类型,这些类型更明确并提供更多自由(例如,实例化),这可能对测试更有用,可以找到here。
std::cout
和std::wcout
使其编译正常。 std::ostringstream
的实例会导致它抱怨模板参数的数量。 std::fstream
实例会导致静态断言失败。请随时以任何方式改进。
答案 1 :(得分: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
和V
将允许在支持可变参数模板参数的编译器上编写通用is_instantiation_of
特征。
要检测stdout是否通过管道传输到文件(当然只能在运行时检测到),请使用isatty
;见how to use isatty() on cout, or can I assume that cout == file descriptor 1?