Search code examples
c++c++17template-meta-programming

Container for classes, with cv-qualifier and reference preserved?


I am relatively new to TMP in c++. I was wondering if there is a way to implement a container for classes(not its instances!) in c++(17, without boost or c++20, preferrably.)

Below is what I am looking for:

int integer = 0xDEADBEEF;
std::string hello ("hello");
boost::any c (integer);
const int c_deadbeef = integer;
int& cr_deadbeef (integer);

using oneClassContainer = decltype( makeClassContainer(integer, hello, c, c_deadbeef, cr_deadbeef) );
// classContainer<int, std::string, boost::any, const int, int&>

using anotherClassContainer = classContainer<int, const int&, const int>;

// anotherClassContainer is passed to a different function.
// in that function:
getType<anotherClassContainer,0> anotherInt = 3; //int
getType<anotherClassContainer,1> constIntRef (anotherInt); //const int&
getType<anotherClassContainer,2> constIntRef= 3; //const int

I would also like the constness to be preserved when classContainer is created using makeClassContainer function arguments. For example, const int b=3; and then amake_tuple(b,1) call returns a tuple<int,int> - the const went missing, and therefore using make_tuple, in any way, is not an option here. (In fact, if we could somehow keep the const and volatile qualifications in make_tuple, this would be the perfect solution)

So to summarize, my question is if the following is possible to implement:

  • a structure that contains classes (not necessarily their instantiations), with
    • ability to accurately pick up cv-qualification and r/lval reference qualification from declared variables
    • ability to return types in some way so that they may be used in declarations
    • ability to be passed around to different contexts (easily achievable, but nonetheless an important condition)

And I would be elated to receive an answer. Thank you!


Solution

  • You can't distinguish integer and cr_deadbeef in a call site, so your desired syntax of decltype( makeClassContainer(integer, hello, c, c_deadbeef, cr_deadbeef) ) is a non-starter. You would have to apply decltype earlier.

    Either directly

    using my_type_1 = std::tuple<decltype(integer), decltype(hello), decltype(c), decltype(c_deadbeef), decltype(cr_deadbeef)>;
    

    Or through a macro

    #include <boost/preprocessor.hpp>
    
    #define ADD_DECLTYPE(a, b, x) decltype(x)
    #define MAKE_TYPE_LIST(...) std::tuple< BOOST_PP_TUPLE_ENUM( BOOST_PP_SEQ_TO_TUPLE( BOOST_PP_SEQ_TRANSFORM( ADD_DECLTYPE, 0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__) ) ) ) >
    using my_type_2 = MAKE_TYPE_LIST(integer, hello, c, c_deadbeef, cr_deadbeef);
    

    See it live