Контейнер для классов с сохранением cv-классификатора и ссылки?

#c #c 17 #template-meta-programming

Вопрос:

Я относительно новичок в TMP на c . Мне было интересно, есть ли способ реализовать контейнер для классов(а не его экземпляров!) в c (предпочтительно 17, без boost или c 20).

Ниже приведено то, что я ищу:

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

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

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

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

Я также хотел бы, чтобы постоянство сохранялось, когда classContainer создается с использованием makeClassContainer аргументов функции. Например , const int b=3; а затем make_tuple(b,1) вызов возвращает a tuple<int,int> const пропал без вести, и поэтому использование make_tuple , в любом случае, здесь не вариант. (На самом деле, если бы мы могли каким-то образом сохранить const квалификацию и volatile make_tuple , это было бы идеальным решением)

Итак, подводя итог, мой вопрос заключается в том, возможно ли реализовать следующее:

  • структура, которая содержит классы (не обязательно их экземпляры), с
    • возможность точного подбора cv-квалификации и справочной квалификации r/lval из объявленных переменных
    • возможность каким-либо образом возвращать типы, чтобы они могли использоваться в объявлениях
    • способность передаваться в разных контекстах (легко достижимое, но тем не менее важное условие)

И я был бы счастлив получить ответ. Спасибо!

Комментарии:

1. В некоторых языках OO определение класса само по себе является объектом, который действует как фабрика, производящая экземпляры. C не таков: класс не является объектом, он не является экземпляром какого-либо мета-класса. В лучшем случае вы могли бы зарегистрировать классы в контейнере класса, а статические функции класса и функции-члены взаимодействовали бы с контейнером класса для ваших целей (ведение журнала, общее количество созданных объектов, текущее количество живых объектов, что угодно). Но такие приборы будут навязчивыми.

2. От вызова функции, integer и cr_deadbeef оба имеют значение lvalue. Существует std::ref то, что можно использовать для добавления ссылок.

3. Другой МАКРОС, где вы можете использовать decltype(integer) ( int ) против decltype(cr_deadbeef) ( intamp; ).

4. getType<anotherClassContainer,0> это в принципе std::tuple_element<I, Tuple> так .

Ответ №1:

Вы не можете различать integer и cr_deadbeef на сайте вызовов, поэтому ваш желаемый синтаксис decltype( makeClassContainer(integer, hello, c, c_deadbeef, cr_deadbeef) ) не является стартовым. Вам придется подать decltype заявление раньше.

Либо напрямую

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

Или через макрос

 #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);
 

Увидеть это вживую