Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine if there is an overloaded function defined for a parameter of a specific type

Tags:

c++

c++17

I have a simple serialization framework that defines specializations of Read and Write template functions for various types including arithmetic, my classes, and std containers like vector, array, map, etc..., so it is possible to do

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

or

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

, for example.

I am looking for a way to determine at compile time is a type serializable or not by implementing something like this:

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

or probably something else.

Is it possible?

The declarations of Read and Write:

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

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

theoretically I can define is_serializable for every type I need in addition to Read and Write, but this requires more typing and makes the code more complicated probably, so having is_serializable defined automatically is more elegant way.

It also can be some Serializer template class with Read and Write functions as members. In this case I need to know if there is a specialization of Serializer for a specific type. For example, I can do something like this with it.

like image 210
Alexey Starinsky Avatar asked Feb 19 '19 14:02

Alexey Starinsky


1 Answers

You can use std::void_t and SFINAE to achieve that. The documentation of std::void_t in cppreference is great.

#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>);
like image 103
metalfox Avatar answered Nov 08 '22 03:11

metalfox