是否可以检查类型或类的重载operator <<是否存在?

蒂莫菲·康欣(Timofey Konshin)

我正在尝试使用c ++ 17在编译时检查是否存在重载的operator <<。理想情况下,它应该类似于以下内容:

template<typename T>
static void serialize_storage(const void* this_, std::ostream& stream) {
    if constexpr (std::is_invocable<...>::value) {
        stream << (*reinterpret_cast<const T*>(this_));
    } else {
        throw std::runtime_error("Type can not be serialized");
    }
}

似乎很难为is_invocable形成参数,因为运算符<<作为std :: ostream的成员或作为“独立”运算符而被重载。因此,我首先尝试了两种不同的功能。

一个例子:

#include <map>
#include <string>
#include <iostream>

using Mmap = std::map<std::string, std::string>;

std::ostream& operator<<(std::ostream& stream, const Mmap& map) {
    stream << map.size();
    return stream;
}

template<typename T>
typename std::enable_if<std::is_invocable<decltype (operator <<(std::declval<std::ostream&>(), std::declval<const T&>())), std::ostream&, const T&>::value, void>::type
serialize_storage(const void* this_, std::ostream& stream) {
    stream << (*reinterpret_cast<const T*>(this_));
}

template<typename T>
typename std::enable_if<std::is_invocable<decltype (std::declval<std::ostream>().operator <<(std::declval<T>())), std::ostream, T>::value, void>::type
serialize_storage(const void* this_, std::ostream& stream) {
    stream << (*reinterpret_cast<const T*>(this_));
}

int main(int , char* [])
{

    Mmap foo;
    char boo = 'A';

    serialize_storage<Mmap>(&foo, std::cerr);
    serialize_storage<char>(&boo, std::cerr);
    std::cerr << std::endl;

    return 0;
}

但是编译器不能替代这两种类型。它看到候选者,但std :: ostream :: operator <<(char)或重载std :: ostream&operator <<(std :: ostream&stream,const Mmap&map)都不符合is_invocable条件。

泰德·林格莫

您可以is_streamable像这样添加特征():

#include <type_traits>

// A helper trait to check if the type supports streaming
template<class T>
class is_streamable {

    // match if streaming is supported
    template<class TT>
    static auto test(int) ->
        decltype( std::declval<std::ostream&>() << std::declval<TT>(), std::true_type() );

    // match if streaming is not supported:
    template<class>
    static auto test(...) -> std::false_type;

public:
    // check return value from the matching "test" overload:
    static constexpr bool value = decltype(test<T>(0))::value;
};

template<class T>
inline constexpr bool is_streamable_v = is_streamable<T>::value;

然后,您可以像这样使用它:

template<class T>
static void serialize_storage(const void* this_, std::ostream& stream) {
    if constexpr (is_streamable_v<T>) {
        stream << (*reinterpret_cast<const T*>(this_));
    } else {
        throw std::runtime_error("Type can not be serialized");
    }
}

演示版

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章