Насколько я знаю, не существует способа сопоставления типов и значений (и шаблон-шаблон) аргументов шаблона вместе.И я долго искал его.
Поэтому я не вижу способа сделать то, что вы хотите, простым и элегантным способом.
Пытаясь ответить на ваш вопрос
Как мы можем получить Transposed
из контейнера с использованием шаблонов?
лучшее, что я могу себе представить, это объявить (не обязательно определять их, принимая во вниманиеиспользуется только внутри decltype()
) пары тривиальных функций следующим образом
template <typename VT,
template <typename...> typename CT>
CT<VT> extract_func (CT<Record<VT>>);
template <typename VT,
template <typename, auto...> typename CT>
CT<VT> extract_func (CT<Record<VT>>);
Первая - удалить часть Record
, когда контейнер CT
принимает список типов с переменным числом (std::vector
и ContainerA
дел);второй предназначен для CT
контейнеров, принимающих (после параметра типа) одно или несколько значений (ContainerB
case).
Очевидно, что это не охватывает все возможные случаи, но тривиально объявить другие extract_func()
функции для покрытия других случаев.
Теперь вы можете объявить Tranposed
следующим образом
template <typename T,
typename CT = decltype(extract_func(std::declval<T>()))>
class Transposed
Обратите внимание, что теперь Transposed
принимает универсальный тип T
, но SFINAE активируется только тогда, когда тип T
соответствует (в качестве аргумента) объявлению extract_func()
.
В теле Transposed
вы можете использовать CT
для объявления x
и y
и T
для аргумента конструктора.
Ниже приведен полный пример компиляции
#include <iostream>
#include <vector>
template <typename value_type=std::uint8_t>
struct Record
{ value_type x, y; };
template <typename value_type, typename value_type2=std::uint8_t>
class ContainerA : public std::vector<value_type>
{ value_type2 b=1u; };
template <typename value_type, std::uint8_t int_value=1u>
class ContainerB : public std::vector<value_type>
{ };
template <typename VT,
template <typename...> typename CT>
CT<VT> extract_func (CT<Record<VT>>);
template <typename VT,
template <typename, auto...> typename CT>
CT<VT> extract_func (CT<Record<VT>>);
template <typename T,
typename CT = decltype(extract_func(std::declval<T>()))>
class Transposed
{
private:
CT x, y;
public:
Transposed (T & recs)
{
x.reserve(recs.size());
y.reserve(recs.size());
x.resize(recs.size());
y.resize(recs.size());
std::size_t i=0u;
for(auto &rec :recs){
x[i] = rec.x;
y[i] = rec.y;
++i;
}
}
};
int main ()
{
std::vector<Record<std::uint8_t>> recsV { {1, 2}, {3, 4} };
Transposed trV{recsV};
std::cout<<"vec"<<std::endl;
ContainerA<Record<std::uint8_t>> recsA { };
Transposed trA{recsA};
std::cout<<"A"<<std::endl;
ContainerB<Record<std::uint8_t>> recsB { };
Transposed trB{recsB};
std::cout<<"B"<<std::endl;
}