Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

type mapping by templates

I'm looking for a way to map types, f.i. having a class Double:

class Double 
{
public:
    typedef double basic_type;
    ...
};

I'd like to be able to have a type caster so that

typeid(TypeToObjectType<double>::type) == typeid(Double)

Any ideas how to accomplish this (through partial specializations etc.) ?

like image 263
Robert Avatar asked Dec 22 '10 19:12

Robert


3 Answers

You can achieve this through specialization :

template<class T>
struct TypeToObjectType;

template<>
struct TypeToObjectType<double> {
    typedef Double type;
};

Note that you have to provide a specialization for each of the types on which you want TypeToObjectType to work. Macros can be helpful here :

#define SPECIALIZE_TYPETOOBJECTTYPE(ObjectType) \
    template<> struct TypeToObjectType<ObjectType::basic_type> { \
        typedef ObjectType type; \
    };

SPECIALIZE_TYPETOOBJECTTYPE(Int)
SPECIALIZE_TYPETOOBJECTTYPE(Double)
like image 85
icecrime Avatar answered Oct 18 '22 00:10

icecrime


This should work very well, however, I haven't tested this method for classes of mine. I have used an idea from the book "C++ Templates: The Complete Guide", paragraph 20.4.2

#include <iostream>
#include <string>
#include <list>
#include <type_traits>

template<typename... Ts>
struct type_mapper;

template<>
struct type_mapper<>
{
    static void mapTo(...);
};

template<typename T, typename... Ts>
struct type_mapper<T, Ts...> : type_mapper<Ts...>
{
    static typename T::second_type mapTo(typename T::first_type);
    using type_mapper<Ts...>::mapTo;
};

template<typename T, typename MapperT>
struct GetTypeOnMap
{
    using type = decltype(MapperT::mapTo(std::declval<T>()));
};

template<typename T, typename MapperT>
using get_type_on_mapping = typename GetTypeOnMap<T, MapperT>::type;

int main(void)
{
    using mapper = type_mapper <  
        std::pair<int, double>,
        std::pair<double, int>,
        std::pair<float, std::string>>;

    using shouldBeDouble = get_type_on_mapping<int, mapper>;
    using shouldBeString = get_type_on_mapping<float, mapper>;
    
    std::cout << shouldBeDouble{2.9};
    std::cout << shouldBeString{"Hello"};

    return 0;
}

EDIT:

Another one solution. More concise and flexible:

#include <complex>
#include <type_traits>
#include <cstdint>
#include <iostream>
#include <string>

template <typename V1, typename V2, typename T>
struct OnTypesEqual : std::bool_constant<std::is_same_v<V1, V2>> {
    using type = T;
};

template <typename T>
struct default_type : std::true_type {
    using type = T;
};

template<typename T>
using TypesMapper = typename std::disjunction<  
    OnTypesEqual<T, double, std::int8_t>,           
    OnTypesEqual<T, float, std::int16_t>,           
    OnTypesEqual<T, std::string, std::int32_t>,           
    OnTypesEqual<T, char, std::int64_t>,           
    default_type<void>
>::type;

int main()
{   
    std::cout << typeid(TypesMapper<double>).name() << std::endl;
    std::cout << typeid(TypesMapper<float>).name() << std::endl;
    std::cout << typeid(TypesMapper<std::string>).name() << std::endl;
    std::cout << typeid(TypesMapper<char>).name() << std::endl;
    
    return 0;
}
like image 22
DisplayName Avatar answered Oct 17 '22 22:10

DisplayName


Sounds like you are looking for something like this:

template<typename T>
struct TypeToObjectType;

// specialization for T=double    
template<>
struct TypeToObjectType<double> {
   typedef Double type;
};

Here TypeToObjectType<double>::type is Double and you can add other specializations for additional mappings.

like image 7
sth Avatar answered Oct 17 '22 23:10

sth