确保参数是控制台的输出流 [英] Ensure argument is an output stream for the console
问题描述
我试图做一个流操纵器的颜色使用输出到控制台。它的工作原理,改变文本和背景的颜色:
I'm trying to make a stream manipulator for colour for use with output to the console. It works, changing the colour of text and the background:
std::cout << ConColor::Color::FgBlue << 123 << "abc"; //text is blue, sticky
问题是签名:
std::ostream &FgBlue(std::ostream &);
此签名允许派生类,例如 std :: ostringstream
,但是没有办法改变字符串流的颜色。该函数将改变控制台的颜色,不管它是否使用这样的参数调用。
This signature allows for derived classes, such as std::ostringstream
as well, but there is no way to change the colour of a string stream. The function would change the colour of the console regardless if it was called with such an argument.
因此,我想确保参数是 std :: cout
, std :: wcout
等。我更喜欢一般在更多 std :: ostream
对象添加到未来标准。
Therefore, I want to ensure the argument is something along the lines of std::cout
, std::wcout
, etc. I would prefer it be general in the case that more std::ostream
objects are added in a future standard.
我尝试了许多涉及 std :: is_same
和 std :: is_base_of
,当前者不工作,只是最终意识到这是无意义的,因为任何参数类型继承自 std :: basic_ostream<>
将被转换为我传递给函数时比较的类型,给出假阳性。
I tried many things involving std::is_same
and std::is_base_of
, when the former wouldn't work, just to eventually realize that it was pointless because any argument type inheriting from std::basic_ostream<>
will be casted to the type I'm comparing against when passed to the function, giving false positives.
这最终导致我的回答如下(variadic模板模板参数但是,还有一些问题:
This eventually led me to my answer below (variadic template template arguments? Wow, that's a mouthful!) There are a couple problems, however:
- 编译器必须支持可变参数模板。
- 如果派生类拥有不同数量的模板参数(例如
std:),编译器会产生隐藏错误。 :ostringstream
,它有3而不是2),因为它没有通过函数签名。 - 可以重定向stdout,到文件,因此即使参数
std :: cout
,也会发生与stringstream情况相同的情况。
- The compiler must support variadic templates. I would prefer the solution work on MSVC.
- The compiler gives cryptic errors in the case that a derived class with a different number of template arguments (such as
std::ostringstream
, which has 3 instead of 2) is used, as it doesn't get past the function signature. - It's possible to redirect stdout, say, to a file, so even if the argument is
std::cout
, the same thing as the stringstream case happens.
我鼓励人们发布任何其他的解决方案,希望比我更好,真正希望至少VS11工作的东西。
I encourage people to post any other solutions, hopefully better than mine, and really hopefully something that works with at least VS11.
推荐答案
这里是检测 std :: basic_ostream
实例化的特征:
Here's a trait for detecting std::basic_ostream
instantiations:
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
trait在支持可变参数模板参数的编译器上。
We use template argument deduction to infer the template parameters on the (non-proper) basic_ostream
base class, if any. As a more general solution, replacing U
and V
with a single variadic parameter would allow writing a generic is_instantiation_of
trait on compilers that support variadic template parameters.
要检测stdout是否管道到一个文件(只能在运行时检测,当然)使用 isatty
;请参阅如何在cout上使用isatty(),或者我可以假设cout ==文件描述符1?
To detect whether stdout is piped to a file (which can only be detected at runtime, of course) use isatty
; see how to use isatty() on cout, or can I assume that cout == file descriptor 1?
这篇关于确保参数是控制台的输出流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!