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.) ?
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)
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.
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;
}
Related
How to check if a template argument is a std::vector<T>::iterator?
For void type, we have std::is_void. Is there something like that for std::vector<T>::iterator?
You could create a trait for that:
#include <vector>
#include <list>
#include <type_traits>
template <class T, class = void>
struct is_vector_iterator: std::is_same<T, std::vector<bool>::iterator> { };
template <class T>
struct is_vector_iterator<T, decltype(*std::declval<T>(), std::enable_if_t<!std::is_same<T, std::vector<bool>::iterator>::value>())>: std::is_same<T, typename std::vector<std::decay_t<decltype(*std::declval<T>())>>::iterator> { };
int main() {
static_assert(is_vector_iterator<std::vector<int>::iterator>::value, "Is not a vector iterator");
static_assert(is_vector_iterator<std::vector<bool>::iterator>::value, "Is not a vector iterator");
static_assert(!is_vector_iterator<std::list<int>::iterator>::value, "Is a vector iterator");
static_assert(!is_vector_iterator<std::list<int>::iterator>::value, "Is a vector iterator");
}
[live demo]
An alternative solution also using std::iterator_traits:
#include <iostream>
#include <vector>
#include <list>
template <typename T>
struct is_vector_iterator
{
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& test(
typename std::enable_if<
std::is_same<T, typename std::vector<typename C::value_type>::iterator>::value
>::type*);
template <typename>
static no& test(...);
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
};
int main() {
std::cout << is_vector_iterator<int>::value << std::endl;
std::cout << is_vector_iterator<int*>::value << std::endl;
std::cout << is_vector_iterator<std::list<int>::iterator>::value << std::endl;
std::cout << is_vector_iterator<std::vector<int>::iterator>::value << std::endl;
return 0;
}
live demo
Better using std::iterator_traits I think:
#include <list>
#include <vector>
#include <iterator>
template <class It, class = void>
struct is_vector_iterator : std::false_type { };
template <class It>
struct is_vector_iterator<It, std::enable_if_t<
std::is_same<
It,
typename std::vector<
typename std::iterator_traits<It>::value_type
>::iterator
>::value
>> : std::true_type { };
int main() {
static_assert(is_vector_iterator<std::vector<int>::iterator>::value, "Is not a vector iterator");
static_assert(is_vector_iterator<std::vector<bool>::iterator>::value, "Is not a vector iterator");
static_assert(!is_vector_iterator<std::list<int>::iterator>::value, "Is a vector iterator");
}
DEMO
You can write a trait for this:
namespace detail
{
template<typename T> constexpr std::false_type is_vector_iterator(T&&, ...)
{
return {};
}
template<typename T>
constexpr auto is_vector_iterator(T&& t, void* = nullptr) ->
decltype(std::is_same<typename std::vector<std::decay_t<decltype(*t)>>::iterator, std::decay_t<T>>{})
{
return {};
}
}
template<typename T>
struct is_vector_iterator : decltype(detail::is_vector_iterator(declval<T>(), 0)) {};
Here I'm getting the decayed type of *t to make vector<type>::iterator and check that for equality with T. It works with the exception of vector<bool> which isn't really a vector anyway.
demo
boost::variant has member types which is some kind of boost::mpl structure.
Is there a way to get an index of type in that structure at compile time, so late in in runtime i could do
if(myVariantInstance.which() == typeIndex)
{
/*...*/
}
Instead of
if(myVariantInstance.type() == typeid(ConcreteType))
{
/*...*/
}
I found solution for getting index of type in boost::variant without boost::mpl if you are interested in.
#include <iostream>
#include <type_traits>
#include <boost/variant/variant.hpp>
using myvariant = boost::variant<int, bool, double, int>;
template <typename T, typename ... Ts>
struct type_index;
template <typename T, typename ... Ts>
struct type_index<T, T, Ts ...>
: std::integral_constant<std::size_t, 0>
{};
template <typename T, typename U, typename ... Ts>
struct type_index<T, U, Ts ...>
: std::integral_constant<std::size_t, 1 + type_index<T, Ts...>::value>
{};
template <typename T, typename ... Ts>
struct variant_first_same_type_idx;
template <typename T, typename Head, typename ... Tail>
struct variant_first_same_type_idx<T, boost::variant<Head, Tail ... >>
: type_index<T, Head, Tail ...>
{};
int main()
{
std::cout << variant_first_same_type_idx<int, myvariant>::value << std::endl;
std::cout << variant_first_same_type_idx<bool, myvariant>::value << std::endl;
std::cout << variant_first_same_type_idx<double, myvariant>::value << std::endl;
}
The output of this program is:
0
1
2
It's a bit convoluted, and there might be a better way, but you could use boost::mpl::copy. Here's something that ought to work, based off of the example from your comment:
#include <boost/variant.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/vector.hpp>
typedef boost::mpl::vector<int, long, char> MyMplVector;
typedef boost::mpl::find<MyMplVector, long>::type MyMplVectorIter;
static_assert(MyMplVectorIter::pos::value == 1, "Error");
typedef boost::variant<int, long, char> MyVariant;
typedef boost::mpl::vector<> EmptyVector;
typedef boost::mpl::copy<
MyVariant::types,
boost::mpl::back_inserter<EmptyVector>>::type ConcatType;
typedef boost::mpl::find<ConcatType, long>::type MyVariantTypesIter;
static_assert(MyVariantTypesIter::pos::value == 1, "Error");
#include <boost/mpl/index_of.hpp>
#include <iostream>
typedef boost::variant<int, std::string> VARIANT;
std::ostream &operator<<(std::ostream &_rS, const VARIANT&_r)
{ switch (_r.which())
{ default:
return _rS << "what the *";
case boost::mpl::index_of<VARIANT::types, int>::type::value:
return _rS << boost::get<int>(_r);
case boost::mpl::index_of<VARIANT::types, std::string>::type::value:
return _rS << boost::get<std::string>(_r);
}
}
PS. I was always curious about people using the visitor access pattern...
PPS. I know that one does not need to implement an output operator as boost::variant already provides one -- just for explanation purposes...
I'm trying to have a class similar to the following
#include <cstdlib>
#include <iostream>
#include <typeinfo>
#include <type_traits>
#include <complex>
template<class K, class T = typename std::conditional<std::is_class<K>::value, typename K::value_type, K>::type>
class A {
public:
K v;
T u;
void type() {
std::cout << typeid(u).name() << std::endl;
}
};
int main() {
A<std::complex<double>> a;
a.type();
A<std::complex<float>> b;
b.type();
A<float> c;
c.type();
A<double> d;
d.type();
return 0;
}
Such that the ouput will be:
d
f
f
d
Stated otherwise, I need the variable u to be of type T if K is of type std::complex<K>, or K otherwise. Can this be achieved with C++11 ? Thanks.
You can use partial specialization to get the right type, maybe like this:
template <typename T, bool> struct ValueType
{
using type = T;
};
template <typename T> struct ValueType<T, true>
{
using type = typename T::value_type;
};
template <class K>
struct A
{
using T = typename ValueType<K, std::is_class<K>::value>::type;
void type()
{
std::cout << typeid(T).name() << std::endl;
}
};
If you want an appropriate data member, you can make the type alias a class member, too, and then declare a data member of type T.
You can easily use partial template specialisation and a trait for this:
template <class T>
struct TypeForU_Class
{
typedef T type;
};
template <class T>
struct TypeForU_Class<std::complex<T>>
{
typedef T type;
};
template <class T>
using TypeForU = typename TypeForU_Class<T>::type;
template <class K, class T>
class A
{
public:
K v;
TypeForU<T> u;
// rest as before
};
basically, i'd like to (at compile time) get the twice-as-wide type from a stdint type. I can do it by hand like this
template <typename T>
class twice_as_wide{};
template<>
class twice_as_wide<uint8_t>
{
public:
typedef uint16_t type;
};
template<>
class twice_as_wide<int8_t>
{
public:
typedef int16_t type;
};
template<>
class twice_as_wide<uint16_t>
{
public:
typedef uint32_t type;
};
ect, I just want to make sure that this doesn't exist yet. I'm using visual studio 2010 C++0X (annoying, i know) and already have a boost dependency. Does anyone know of an existing implementation of this?
If you don't mind another boost dependency, then you could do this:
#include <type_traits>
#include <boost/integer.hpp>
template <typename T, bool is_unsigned = std::is_unsigned<T>::value>
struct twice_as_wide
{
typedef typename boost::uint_t< 2 * std::numeric_limits<T>::digits>::exact type;
};
template<typename T>
struct twice_as_wide<T, false>
{
typedef typename boost::int_t< 2 * (std::numeric_limits<T>::digits + 1)>::exact type;
};
template< typename T>
using twice_as_wide_t = typename twice_as_wide<T>::type;
I'd say, use Boost Integer. Demo that keeps signed-ness of the source type: Live on Coliru
#include <boost/integer.hpp>
#include <limits>
namespace helpers
{
// wrappers around Boost Integer http://www.boost.org/doc/libs/1_54_0/libs/integer/doc/html/boost_integer/integer.html#boost_integer.integer.sized
template <bool is_signed, int bin_digits> struct select_twice;
template <int bin_digits> struct select_twice<true, bin_digits> {
using type = typename boost::int_t<bin_digits + 1>::least;
};
template <int bin_digits> struct select_twice<false, bin_digits> {
using type = typename boost::uint_t<bin_digits>::least;
};
}
template <typename Int>
using select_twice = helpers::select_twice<std::numeric_limits<Int>::is_signed, std::numeric_limits<Int>::digits*2>;
template <typename Int>
using twice_t = typename select_twice<Int>::type;
int main()
{
static_assert(std::is_same<uint16_t, twice_t<uint8_t>>::value, "oops");
static_assert(std::is_same<uint32_t, twice_t<uint16_t>>::value, "oops");
static_assert(std::is_same<uint64_t, twice_t<uint32_t>>::value, "oops");
}
I have code, that compiles and runs as expected in gcc and doesn't compile in MSVC 2012 RC, i can't explain why, so it's bug in MSVC, or my code is incorrect?
#include <boost/mpl/vector.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/is_sequence.hpp>
#include <boost/mpl/size.hpp>
#include <boost/utility/enable_if.hpp>
#include <vector>
#include <iostream>
namespace mpl = boost::mpl;
template<typename T,
typename = void>
struct Some
{
typedef std::vector<T> type;
};
template<typename T>
struct Some<T, typename boost::enable_if_c<mpl::is_sequence<T>::type::value>::type> :
public Some<typename mpl::front<T>::type>::type
{
};
int main()
{
typedef mpl::vector<int, double> vect_t;
typedef Some<vect_t> vector;
vector vect;
vect.push_back(1);
std::cout << "int: " << vect.at(0) << std::endl;
}
http://liveworkspace.org/code/45d78872a2c7f30192277a81c655b471
MSVC says, that push_back and at are not members of Some<vect_t>.
EDIT.
It looks like bug in MSVC 2012 since
#include <boost/mpl/vector.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/is_sequence.hpp>
#include <boost/mpl/size.hpp>
#include <boost/utility/enable_if.hpp>
#include <vector>
#include <iostream>
namespace mpl = boost::mpl;
template<typename T, typename = void>
struct Some
{
typedef std::vector<T> type;
};
template<typename T>
struct Some<T, typename boost::enable_if_c<mpl::is_sequence<T>::type::value>::type> :
public std::vector<int>
{
};
int main()
{
typedef mpl::vector<int, double> vect_t;
typedef Some<vect_t>::type vector;
vector vect;
vect.push_back(1);
std::cout << "int: " << vect.at(0) << std::endl;
}
gives errors, that i can't push_back int into std::vector<boost::mpl::vector<int, double> >, so it choose general-case, not specialization...
EDIT.
Strange... But this works as expected
template<typename T>
struct Some<T, typename std::enable_if<boost::mpl::is_sequence<T>::value>::type> :
public std::vector<int>
{
};
So, i can't explain why, but MSVC 2012 cannot works with nested expressions in enable_if (or possibly in template parameters).
template<typename T>
struct is_int : public std::integral_constant<bool, false>
{
};
template<>
struct is_int<int> : public std::integral_constant<bool , true>
{
};
template<typename T, typename = void>
struct Some
{
typedef void type;
};
template<typename T>
struct Some<T, typename std::enable_if<is_int<T>::type::value>::type>
{
static_assert(is_int<int>::type::value, "asserted");
typedef T type;
};
int main()
{
static_assert(is_int<T>::type::value, "ass");
Some<int>::type t = 0;
}
I compile and run your code in MSVC 2010 successfully, so probably this is a bug in RC version of MSVC 2012. so event try it in MSVC 2012 final or wait for MSVC 2012 Express.