Мне нужно написать класс, который содержит массив фиксированной длины (длина массива определяется аргументом шаблона), и массив должен быть инициализирован сразу, с ограничением, что каждый член инициализируется. Также обратите внимание, что я использую c ++ 17.
Я не слишком знаком со всеми возможностями шаблонов c ++, но я действительно хотел бы повторно реализовать эту функциональность из чистого C для управления несколькими экземплярами. этой структуры данных становится утомительным.
Вот пример кода:
#include <iostream>
enum TraitEnum
{
Trait_0,
Trait_1,
Trait_2,
Trait_3,
Trait_N,
};
template<typename TraitType, TraitType NType>
class TraitField
{
public:
struct TraitStruct
{
TraitType Trait;
bool Status;
};
TraitField(const TraitStruct TraitArray[NType]) :
traitArray{ TraitArray }
{}
private:
TraitStruct traitArray[NType];
};
int main()
{
TraitField<TraitEnum, Trait_N> myTraitField({
{ Trait_0, true },
{ Trait_1, true },
{ Trait_2, true },
{ Trait_3, true },
});
std::cout << "test" << std::endl;
return 0;
}
Компилятор выдает следующую ошибку:
error C2664: 'TraitField<TraitEnum,Trait_N>::TraitField(TraitField<TraitEnum,Trait_N> &&)': cannot convert argument 1 from 'initializer list' to 'const TraitField<TraitEnum,Trait_N>::TraitStruct []'
Я мог бы инициализировать массив с помощью initializer-list, но не потеряю ли я ограничение на то, что необходимо передать массив точно такого же размера? Для меня очень важно, чтобы массив внутри класса полностью инициализировался во время компиляции.
Также я не уверен, может ли компилятор определить правильный тип безымянного массива, который я передаю в конструктор.
РЕДАКТИРОВАТЬ: забыл упомянуть, для ограничений проекта, я не могу использовать стандартную библиотеку шаблонов, поэтому std::vector
или std::array
не допускается.
EDIT2: после определяя пользовательский тип контейнера для массива, он работает:
#include <iostream>
enum TraitEnum
{
Trait_0,
Trait_1,
Trait_2,
Trait_3,
Trait_N,
};
template<typename ElemType, size_t NElem>
struct ArrayType
{
ElemType data[NElem];
};
template<typename TraitType, TraitType NType>
class TraitField
{
public:
struct TraitStruct
{
TraitType Trait;
bool Status;
};
typedef ArrayType<TraitStruct, NType> TraitArrayType;
TraitField(const TraitArrayType &TraitArray) :
traitArray{ TraitArray }
{}
private:
TraitArrayType traitArray;
};
int main()
{
TraitField<TraitEnum, Trait_N>::TraitArrayType testArray{
{
{ Trait_0, true },
{ Trait_1, true },
{ Trait_2, true },
{ Trait_3, true },
}
};
TraitField<TraitEnum, Trait_N> myTraitField(testArray);
std::cout << "test" << std::endl;
return 0;
}
Еще одно, это то, что я хотел бы избежать объявления "testArray
", если это возможно, но если я инициализирую объект непосредственно с помощью безымянные массивы, компилятор пытается преобразовать его непосредственно в список инициализаторов вместо массива моего определенного типа.
EDIT3: Спасибо, max66, ваше решение, похоже, именно то, что я хотел. Я только что сделал некоторые изменения, а именно, необходимо повторно реализовать make_index_sequence и index_sequence отсюда: подробности о std :: make_index_sequence и std :: index_sequence (необходимо также убрать часть std :: decay, поскольку он будет содержать только примитивные типы) также нужно, чтобы объект не был constexpr, так как мне нужно изменить его время выполнения (отражено в примере кода)
#include <iostream>
enum TraitEnum
{
Trait_0,
Trait_1,
Trait_2,
Trait_3,
Trait_N,
};
template<typename TraitType, TraitType NType>
class TraitField
{
public:
template <std::size_t... Ns>
struct index_sequence {};
template <std::size_t N, std::size_t... Is>
auto make_index_sequence_impl()
{
if constexpr (N == 0) // stop condition
{
return index_sequence<Is...>();
}
else // recursion
{
return make_index_sequence_impl<N - 1, N - 1, Is...>();
}
}
template <std::size_t N>
using make_index_sequence = decltype(make_index_sequence_impl<N>());
struct TraitStruct
{
TraitType Trait;
bool Status;
};
constexpr TraitField(TraitStruct const (&arr)[NType])
: TraitField{ arr, std::make_index_sequence<NType>{} }
{ }
public:
TraitStruct traitArray[NType];
template <std::size_t ... Is>
constexpr TraitField(TraitStruct const (&arr)[NType],
std::index_sequence<Is...>)
: traitArray{ arr[Is]... }
{ }
};
int main()
{
TraitField<TraitEnum, Trait_N> myTraitField{ {
{ Trait_0, true },
{ Trait_1, true },
{ Trait_2, true },
{ Trait_3, true },
} };
for (auto trait : myTraitField.traitArray)
{
std::cout << trait.Trait << " " << trait.Status << std::endl;
}
std::cout << std::endl;
myTraitField.traitArray[Trait_1].Status = false;
for (auto trait : myTraitField.traitArray)
{
std::cout << trait.Trait << " " << trait.Status << std::endl;
}
return 0;
}