(This question has an answer by Nim which mentions boost::mpl::map.)
Is there a compile-time container in standard C++ which can hold types?
A usage example would be:
compiler::vector foo{char, short, long, long long};
template <int N>
void bar(foo[N] param){/*do something and return foo[N]*/}
C++ Standard Library Containers. The Standard Library provides various type-safe containers for storing collections of related objects. The containers are class templates; when you declare a container variable, you specify the type of the elements that the container will hold. Containers can be constructed with initializer lists.
They are implemented as class templates, which allows great flexibility in the types supported as elements. The container manages the storage space for its elements and provides member functions to access them, either directly or through iterators (reference objects with similar properties to pointers).
In C++98/03, you can use std::equal or std::mismatch to compare dissimilar container types and/or element types. In C++11, you can also use std::is_permutation. But in all these cases the functions assume the containers are the same length. If the second range is shorter than the first, then undefined behavior results.
In general, elements inserted into a C++ Standard Library container can be of just about any object type if they are copyable. Movable-only elements—for example, those such as vector<unique_ptr<T>> that are created by using unique_ptr<> will work as long as you don't call member functions that attempt to copy them.
In c++11 you can use std::tuple : (disclaimer: not tested)
#include <tuple>
#include <type_traits>
std::tuple<char, short, long, long long> foo;
// reference type
template <int N>
void bar(decltype(std::get<N>(foo)) param){...}
// value type
template <int N>
void bar(std::remove_reference<decltype(std::get<N>(foo))>::type param)
Note that this is not completely what you want since you will either have only value or reference types, even if both are mixed in the tuple declaration of foo.
The value of the tuple are never used. I think with compiler optimization, foo will actually never be instanciated in the object code
As a type container, the standard provides you with std::tuple
and -- as bogdan commented -- you can access the type elements using std::tuple_element
.
using foo = std::tuple<char, short&, const long&&, long long>;
template <int N>
typename std::tuple_element<N,foo>::type bar(){/*...*/}
Even if std::tuple_element
did not exist, you could easily build your own:
/// We want a metafunction to accept an index N into our type list LIST
template <unsigned N, typename LIST> struct
tuple_element;
/// Specialization for the case where N==0
template <template <typename ...> class LIST_T,typename T,typename...ELMS> struct
tuple_element<0,LIST_T<T,ELMS...>> {
using type = T; // just take the first type from the list
};
template <unsigned N, template <typename ...> class LIST_T,typename T,typename...ELMS> struct
tuple_element<N,LIST_T<T,ELMS...>> {
/// fallback for N>0: delegate the result type recursively until N->0
using type = typename tuple_element<N-1,LIST_T<ELMS...>>::type;
};
// create a convenience wrapper for the template
template <unsigned N, typename LIST> using
type_at = typename tuple_element<N, LIST>::type;
Now you can define your type list, e.g. like so:
using foo = std::tuple<char, short&, const long&&, long long>;
And you can easily access it's elements using type_at<N, foo>
:
static_assert(std::is_same< type_at<0,foo>, char>::value,"error");
static_assert(std::is_same< type_at<1,foo>, short&>::value,"error");
static_assert(std::is_same< type_at<2,foo>, const long&&>::value,"error");
static_assert(std::is_same< type_at<3,foo>, long long>::value,"error");
template <int N>
type_at<N,foo> bar(){/*...*/}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With