lundi 3 mai 2021

Check if two different types are contained in the same container while dealing with nested containers as well

I'm trying to do some type conversions to interface different C++ libraries together where each library will have different implementations of similar classes such as Point classes, where for this example, libraryA will have class PointA, and libraryB will have PointB. I find myself having to write a lot of tedious functions to deal with different containers, as well as nested containers, of each type, in order to copy data from one container to the other. I was able to find and modify a bit of code that allowed me to easily make basic type conversions as follows:

template<typename from, typename to>
struct type_to_type_converter
{
    from to_convert;
    operator to();
};

template<typename from>
struct AnyTypes
{
    from to_convert;
    template<typename to, typename C = type_to_type_converter<from, to>>
    operator to()
    {
        C c = C{std::move(to_convert)};
        return c;
    }
};

template<typename from>
inline AnyTypes<from> from_type(from f)
{
    return AnyTypes<from>{std::move(f)};
}

This essentially lets me create some type operator functions such that any pairs of types can be converted to and from each other. For the PointA/PointB case, I would define two operator functions as follows:

template<>
type_to_type_converter<PointA, PointB>::operator PointB()
{
    return PointB(to_convert.x(), to_convert.y()); //NOTE: to_convert is of type PointA
}

template<>
type_to_type_converter<PointB, PointA>::operator PointA()
{
    return PointA(to_convert.x, to_convert.y); //NOTE: to_convert is of type PointB
}

As a contrived example, you'll notice that the two Point classes have different interfaces for exposing their x and y coordinates. The function template "from_type" then allows me to do simple conversions like such:

PointA a(1,2);
PointB b = from_type(a);

My problem is that in order to deal with conversions from a std::vector to a std::vector, I'd have to define a new pair of operator functions for those new types explicitly like this:

template<>
type_to_type_converter<std::vector<PointA>, std::vector<PointB>>::operator std::vector<PointB>()
{
    std::vector<PointB> v;
    for (auto p : to_convert)
    {
        v.push_back(from_type(p)); //NOTE: Assumes previous definition of from_type() for PointA -> PointB
    }
    return v;
}

With a matching PointB -> PointA function to deal with the reverse conversion. I'd then have to repeat this for std::vectorstd::vector<PointA> <-> std::vectorstd::vector<PointB>, and any other combination of containers. My knowledge of templates is actually very poor and I've only managed to get this far by pilfering code from other SO posts and cobbling them together. So my question is: Would it be possible to automate dealing with the different containers by changing the AnyTypes struct operator to() based on some compile time type checking to determine if the containers are the same recursively such that each nested container is iterated through/stripped away until the base type is reached and the from_type function for the pair can be called? My requirements so far have only required that the conversion handle matched nested containers:

std::vector<std::vector<PointA>> <-> std::vector<std::vector<PointB>> 

or

std::vector<std::queue<PointA>> <-> std::vector<std::queue<PointB>> 

and not mixed conversions such as:

std::vector<std::vector<PointA>> <-> std::vector<std::queue<PointB>>

in the event that makes a solution easier to come up with.

As I'm writing this question, some things that come to mind include a mix of modifying the type_to_type_converter struct to include a typename for the container type, having a variadic template for the AnyTypes struct that could allow for specializing the implementations to use iterators when it detects a container type template as opposed to a "Point" (or any other class) type.

I've found something that allows to check if two containers are the same for two different types, but after running some tests, this fails to handle nested containers and only looks at the outer most template. Check if two types are of the same template The reason I mention this is I'd like to ensure that these type conversions aren't misused by client code and that some type checking is in place for a solution that only handles matched nesting of containers such that it would cause compile time errors and not difficult to track down run time errors. Another restriction to the solution is that I'm currently tied to C++11.

Now in the event someone with strong C++ code-fu sees this post, my ultimate end goal would be to have the ability to do implicit conversions using the assignment operator rather than explicitly call from_type, as I've seen done in the nlohmann json library (https://github.com/nlohmann/json), but I'm not greedy, just hopeful. Any help with this problem would be greatly appreciated.

Aucun commentaire:

Enregistrer un commentaire