如何检测类型是否可以流传输到std :: ostream? [英] How can I detect if a type can be streamed to an std::ostream?
问题描述
我想写一个类型trait来检测类型是否具有适合用于输出流的重载操作符<<()。
I'm trying to write a type trait to detect if a type has overloaded operator<<() suitable to use to an output stream.
m缺少一些东西,因为我总是得到一个简单的空类没有任何运算符。
I'm missing something because I'm always getting true for a simple empty class with no operators at all.
这里的代码:
template<typename S, typename T>
class is_streamable
{
template<typename SS, typename TT>
static auto test(SS&& s, TT&& t)
-> decltype(std::forward<SS>(s) << std::forward<TT>(t));
struct dummy_t {};
static dummy_t test(...);
using return_type = decltype(test(std::declval<S>(), std::declval<T>()));
public:
static const bool value = !std::is_same<return_type, dummy_t>::value;
};
class C {};
int main() {
std::cout << is_streamable<std::stringstream, C>::value << std::endl;
return 0;
}
输出:
1
这里是在ideone:https://ideone.com/ikSBoT
Here it is in ideone: https://ideone.com/ikSBoT
我做错了什么?
推荐答案
显然这个重载的运算符<<
traling中的表达式返回类型valid:
It's apparently this overload of operator<<
that's stepping in your way and making the expression in traling return type valid:
template< class CharT, class Traits, class T >
basic_ostream< CharT, Traits >& operator<<( basic_ostream<CharT,Traits>&& os,
const T& value );
请参阅此参考页。它是一个简单的转发器(调用 os<
See (3) on this reference page. It's a simple forwarder (calling os << value
) that was added in C++11 to allow insertion to rvalue-streams because they don't bind to overloads taking an lvalue reference.
所以,问题是 std :: declval< SS>()
返回一个右值引用和这个重载踢。调用本身是良好的形式,但因为函数本身没有被实例化,你不会得到一个错误,即使值不可流化。
So, the problem is that std::declval<SS>()
returns an rvalue reference and this overload kicks in. The call itself is well-formed, but because the function itself does not get instantiated you don't get an error even if value is not streamable.
如果您明确要求引用值为$ lt code> std :: declval< SS&>()。
This can be sidestepped if you explicitly ask for lvalue reference: std::declval<SS&>()
.
我也建议一个稍微不同的实现,而不传递流和值到 test
。您可以在 decltype
中直接使用 declval
。与逗号运算符一起,它看起来像这样:
I'd also suggest a slightly different implementation, without passing stream and value to test
. You can use declval
directly inside decltype
. Together with comma operator, it looks like this:
#include <type_traits>
#include <utility>
#include <iostream>
#include <sstream>
template<typename S, typename T>
class is_streamable
{
template<typename SS, typename TT>
static auto test(int)
-> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() );
template<typename, typename>
static auto test(...) -> std::false_type;
public:
static const bool value = decltype(test<S,T>(0))::value;
};
class C {};
int main() {
std::cout << is_streamable<std::stringstream, C>::value << std::endl;
return 0;
}
这篇关于如何检测类型是否可以流传输到std :: ostream?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!