there is some enum class like
enum class first{
a,
b,
...
};
enum class second{
c,
d,
...
};
the class seems like
template<first N, second M> class A{
public:
A(){}
A(int n) {
var = n;
}
int var;
};
I wanto use it in gtest which is
template<typename T> class TestA : public ::testing::Test {};
TYPED_TEST_CASE_P(TestA);
TYPED_TEST_P(TestA, SomeTest){
TypeParam x(0);
EXPECT_EQ(x.var,0);
}
REGISTER_TYPED_TEST_CASE_P(TestA, SomeTest);
typedef ::testing::Types<A<first::a, second::c>, A<first::b, second::d>...> MyTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My, TestA, MyTypes);
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
how can i generate combinations of all possible template parameters so it easily add test case by increasing enum number maybe there is 3 or more param
::testing::Types<A<first::a, second::c>, A<first::a, second::c>, A<first::b, second::c>, A<first::b, second::c>>
::testing::Types<A<first::a, second::c, third::e>, A<first::a, second::c, third::f>...>
I try to contain them in template struct looks like this then I cam make impl just like
::testing::Combine(Base<first::a, first::b, ...>,Base<second::c, second::d, ...>;)
to generate
::testing::Types<A<first::a, second::c>, A<first::c, second::d>.....>
maybe there is 3 or more param
::testing::Types<A<000>, A<001>, A<010>, A<011>>.....
CodePudding user response:
Provided your enums all have 0 as start value and do not contain gaps in between any two values then you can generate via the following approach (for any number of arguments/enums); note that this goes via an intermediate step of std::tuple
s as for these there's std::tuple_cat
available (instead of having to write an own, direct concatenation for testing::Types
template):
template <size_t N, size_t ... NN>
class Generate<N, NN...>
{
template <size_t ... NNN>
friend class Generate;
template <size_t S>
class Concat
{
template <size_t ... SS>
auto concat(A<SS...>)
{
return A<S, SS...>();
}
public:
template <typename ... T>
auto operator()(std::tuple<T...> const& t)
{
return std::apply
(
[this](auto ... t)
{
return std::tuple(concat(t)...);
},
t
);
}
};
template <size_t ... S>
static auto generate(std::index_sequence<S...>)
{
using Base = typename Generate<NN...>::internal;
return std::tuple_cat(Concat<S>()(Base())...);
}
template <typename ... T>
static auto translate(std::tuple<T...>)
{
return Types<T...>();
}
using internal = decltype(generate(std::make_index_sequence<N>()));
public:
using type = decltype(translate(internal()));
};
The nested class allows to specify the single constants without having to specify the variadic types which would have been pretty cumbersome (if possible at all...).
Demonstration (with custom A
and Types
types) on godbolt.
CodePudding user response:
Here is my template tool, note this doesn't require use of integer sequence:
namespace detail {
template <auto... values>
struct value_list {
template <auto newValue>
using append = value_list<values..., newValue>;
template <template <auto...> typename T>
using apply_on = T<values...>;
};
template <typename... Ts>
struct concat_types_list;
template <template <typename...> typename Tem, typename... As>
struct concat_types_list<Tem<As...>> {
using type = Tem<As...>;
};
template <template <typename...> typename Tem, typename... As, typename... Bs, typename... Remaning>
struct concat_types_list<Tem<As...>, Tem<Bs...>, Remaning...> {
using type = typename concat_types_list<Tem<As..., Bs...>, Remaning...>::type;
};
template <typename... Ts>
using concat_types_list_t = typename concat_types_list<Ts...>::type;
template <typename... Ts>
struct value_generator {
using type = value_generator;
template <auto value>
using for_each_append = value_generator<typename Ts::template append<value>...>;
template <auto... Values>
using mutiply = concat_types_list_t<for_each_append<Values>...>;
template <template <typename...> typename Out, template <auto...> typename In>
using compose = Out<typename Ts::template apply_on<In>...>;
};
}
using value_generator_t = detail::value_generator<detail::value_list<>>;
Use is quite nice:
using MyTypes = value_generator_t
::mutiply<first::a, first::b, first::x, first::y>
::mutiply<second::c, second::e, second::f>
::compose<::testing::Types, A>;