Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does C++ have a standard, compile-time type container?

Tags:

c++

(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]*/}
like image 776
Jonathan Mee Avatar asked Feb 27 '15 16:02

Jonathan Mee


People also ask

What are containers in C++ standard library?

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.

Why are containers implemented as class templates in Java?

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).

How to compare two containers with different types in C++?

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.

What types of objects can be inserted into a C++ container?

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.


2 Answers

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

like image 108
Bérenger Avatar answered Sep 24 '22 14:09

Bérenger


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(){/*...*/}
like image 35
Julian Avatar answered Sep 20 '22 14:09

Julian