Рассмотрим код ниже:
template <typename T>
class A{
...
}
template <class U>
class B{
...
}
int main {
B<A<int>> a;
...
}
Как я могу получить параметр шаблона A (в данном случае int) внутри B, если A<int> является параметром шаблона для B? Я мог бы параметризовать B следующим образом, но мне кажется, что я отправляю ненужную часть информации.
template <class AA, typename T>
class B { ... }
Причина, по которой я не просто использую template <typename T>
для класса B, заключается в том, что у меня есть указатель на класс A внутри B, и я хочу использовать параметр шаблона class AA
, чтобы увидеть, является ли этот указатель константным или нет, следовательно, иметь правильный тип для члена указатель в Б.
@TanveerBadar, спасибо за ответ. класс B должен всегда иметь A<T> в качестве параметра шаблона. Именно T является реальным параметром (как и постоянство A<T>).
Так почему бы не использовать template <typename T> class B{ A<T> X; ...};
?
@Damien, потому что у меня есть «A<T>* X» или «const A<T>* X» в зависимости от того, является ли A константой или нет. Предположим, что A — очень большой класс, и я хочу иметь указатель на него внутри B, но в то же время A может быть константным или нет. Я задал еще один вопрос по этому поводу здесь: stackoverflow.com/q/65286216/10755448
Я не вижу, что это меняет. У вас может быть `template <typename T> class B{ A<T> *X; константа A<T> *Y; ...}; ...
@ Дэмиен, возможно, я чего-то не знаю или не понимаю. Но позвольте мне уточнить. У меня есть только X, он указывает на A, что A может быть константой или нет, поэтому тип X зависит от константности A, на которую он указывает. Предположим, что B создан внутри A и внутри A.
Я думаю, что следующее делает то, что вы хотите:
#include<type_traits>
template<class>
class A{};
template<class>
struct get_inner;
template<template<class> class TT, class T>
struct get_inner<TT<T>> {
using outer = TT<T>;
using inner = T;
};
template<class TT>
struct B {
using A = TT;
using inner = typename get_inner<std::decay_t<A>>::inner;
};
int main(int argc, char *argv[])
{
static_assert(std::is_const_v<typename B<const A<int>>::A>);
static_assert(!std::is_const_v<typename B<A<int>>::A>);
}
Обратите внимание на std::decay_t
, он не будет работать с параметром const
напрямую (поэтому мы не можем просто специализировать B
таким образом). Может быть, decay_t
немного сильно, но это работает ^^
Попробуй это
template <typename X> class B;
template <template <typename> class XX, typename T>
class B<XX<T>>
{
// your implementation
};
B<A<int>> a;
Есть несколько способов, в зависимости от которых вы можете изменить:
Быстрый путь, специализация B
template <class> class B;
template <class T>
class B<A<T>>
{
// Use directly T
//...
};
Добавить информацию напрямую в A
(как стандартные контейнеры делают с value_type
)
template <typename T>
struct A
{
using my_type = T;
};
// Then in `B<U>`, use `typename U::my_type`
Используйте внешние признаки для извлечения информации из A
(как std::iterator_traits
) (что также позволяет обрабатывать встроенные типы):
template <typename T>
struct ATrait;
template <typename T>
struct ATrait<A<T>>
{
using my_type = T;
};
// Possibly a generic one
template <template <typename> class C, typename T>
struct ATrait<C<T>>
{
using my_type = T;
};
// Then in `B<U>`, use `typename ATrait<U>::my_type`
Вы можете частично специализировать его, как
template<typename T> class B<A<T>> { /* whatever */ };
. И в вашем собственном решении тоже нет ничего плохого. Ваш вопрос слишком расплывчатый, чтобы дать более конкретный ответ.