检查是否为类T定义了ostream << T

时间:2018-07-07 23:54:57

标签: c++

是否可以检查是否为类T定义了ostream << T,并使用该信息来决定是否构建模板?

例如,假设我有一些围绕不同类型T的包装器类

template<class T>
Wrapper
{
public:

    T m_value;

    Wrapper(const T & value) : m_value{ value } { }
};

并且我想定义一个运算符<<()朋友函数以打印到ostream

template<class T>
ostream & operator<<(ostream & out, const Wrapper<T> & wrapper)
{
    out << wrapper.value;

    return out;
}

是否有一种方法只能为定义了ostream << T的T类型构造该模板?

1 个答案:

答案 0 :(得分:4)

做这样的事情的蓝图首先是这样:

#include <utility>
#include <iostream>

template<typename T, typename=void>
struct can_output_to_ostream : public std::false_type {};

template<typename T>
struct can_output_to_ostream<T, std::void_t
               <decltype(std::declval<std::ostream &>() <<
                     std::declval<T &&>())>>
    : public std::true_type{};


struct x {};

int main()
{
    std::cout << can_output_to_ostream<int>::value << std::endl;
    std::cout << can_output_to_ostream<x>::value << std::endl;
}

std::void_tC++17,但简短的搜索将找到在早期C ++修订版中实现它的示例。

此示例的输出是:

1
0

因为您可以<<int,但是没有为x定义这样的重载。

在您的情况下,您可以使用此示例,并使包装器类继承自以类似方式定义的implements_output_to_ostream类。默认实现不执行任何操作,而支持<<的类的实现则相应地实现<<运算符。

您的Wrapper类继承自implements_output_ostream。也许您的Wrapper类将提供自己的<<方法,该方法将其成员传递给父类的方法,该方法将完全为具有<<能力的类定义,否则未定义,从而导致编译如果尝试为未实现<<重载的类引用它,则会发生错误。