【问题标题】:Determine if there is an overloaded function defined for a parameter of a specific type确定是否为特定类型的参数定义了重载函数
【发布时间】:2019-02-19 14:42:43
【问题描述】:

我有一个简单的序列化框架,它为各种类型定义了 Read 和 Write 模板函数的特化,包括算术、我的类和 std 容器,如 vector、array、map 等......,所以可以这样做

std::vector<std::string> v{ "a1", "b123", "c12345" };
Read(stream, v);
Write(stream, v);

std::map<int, MyClass> m;
Read(stream, m);
Write(stream, m);

,例如。

我正在寻找一种方法来确定在编译时是否是可序列化的类型,方法是实现如下:

template <class T>
constexpr bool is_serializable()
{
    if (Read<T> and Write<T> are defined) 
        return true;
    return false;
}

或者可能是别的什么。

有可能吗?

Read 和 Write 的声明:

    template <typename T>
    void Read(InputStream & s, T & val);

    template <typename T>
    void Write(OutputStream & s, T val);

理论上,除了 Read 和 Write 之外,我还可以为我需要的每种类型定义 is_serializable,但这需要更多的输入,并且可能使代码更复杂,因此自动定义 is_serializable 是一种更优雅的方式。

它也可以是一些以读写函数为成员的序列化器模板类。在这种情况下,我需要知道是否有针对特定类型的 Serializer 专门化。例如,我可以用它做something like this

【问题讨论】:

    标签: c++ c++17


    【解决方案1】:

    您可以使用std::void_t 和 SFINAE 来实现这一点。 cppreferencestd::void_t 的文档很棒。

    #include <type_traits>
    #include <iostream>
    
    void Read(std::istream &,double &) {}
    void Write(std::ostream &,double) {}
    
    template <typename T,typename= void>
    struct is_serializable_t: std::false_type {};
    
    template <typename T>
    struct is_serializable_t<T,std::void_t<
        decltype(Read(std::declval<std::istream &>(),std::declval<T &>())),
        decltype(Write(std::declval<std::ostream &>(),std::declval<T>()))>>:
        std::true_type {};
    
    template <typename T>
    inline constexpr bool is_serializable = is_serializable_t<T>::value;
    
    static_assert(is_serializable<double>);
    static_assert(!is_serializable<int>);
    

    【讨论】:

    • 看一个函数的返回类型是如何定义的例子,但是函数本身并不能编译,wandbox.org/permlink/9pAFyjTUDyf9Erxpthis
    • 可能是一个更好的例子(取消注释上次读取调用)wandbox.org/permlink/yuj9T45QnTywO7hE
    • 总的来说,你的回答很棒!
    • @AlexeyStarinsky 要编译您的示例,您需要声明 template &lt;class T, class Compare, class Alloc&gt; int Read(Stream &amp; s, std::set&lt;T *, Compare, Alloc&gt; &amp; coll)
    • @AlexeyStarinsky 啊。好的。然后您可以将其声明为int Read(Stream &amp; s, std::set&lt;std::remove_pointer_t&lt;T&gt;, Compare, Alloc&gt; &amp; coll),以避免将int * 推导出为T
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 2015-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多