在 C++ 中,从枚举数组生成各种特殊 class 的 constexpr 元组
In c++ generate constexpr tuple of various specialized class from enum array
我是 C++ 模板元编程的新手。
我试图从枚举数组中生成专门 class 的 constexpr 元组。
我正在使用 c++14。
这是我的示例代码。
我尝试使用 http://en.cppreference.com/w/cpp/utility/integer_sequence,但是专门的 class 有问题。
#include <iostream>
#include <utility>
#include <tuple>
enum class ClassType{ kA, kB, kC };
template<ClassType Type>
class Event;
template<>
class Event<ClassType::kA>{ void func() { std::cout << "A" << std::endl; } };
template<>
class Event<ClassType::kB>{ void func() { std::cout << "B" << std::endl; } };
template<>
class Event<ClassType::kC>{ void func() { std::cout << "C" << std::endl; } };
class EventList
{
public:
constexpr EventList() : size_(0), list_{ClassType::kA,} {}
ClassType list_[255];
int size_;
};
template <std::size_t Index, EventList&& List>
constexpr auto GetEvent()
{
return Event<List.list_[Index]>();
}
constexpr auto CreateEventList()
{
EventList list;
list.list_[0] = ClassType::kA;
list.list_[1] = ClassType::kB;
list.list_[2] = ClassType::kC;
list.size_ = 3;
return list;
}
int main()
{
constexpr auto eventlist =CreateEventList();
constexpr std::tuple<Event<eventlist.list_[0]>,
Event<eventlist.list_[1]>,
Event<eventlist.list_[2]>
// ... until i==listsize-1
> gentuple;
constexpr auto t = CreateTupleFromArray(eventlist);
}
我也尝试过类似的其他方式。
template<std::size_t SIZE>
constexpr auto CreateArray()
{
std::array<ClassType, SIZE> array = {ClassType::kA,};
for( auto i=0 ; i<SIZE ; ++i )
array[i] = static_cast<ClassType>(i % 3);
return array;
}
template<typename Array, std::size_t... I>
decltype(auto) a2t_impl(const Array& a, std::index_sequence<I...>)
{
return std::make_tuple(Event<a[I]>()...);
}
template<typename T, std::size_t N, typename Indices = std::make_index_sequence<N>>
decltype(auto) a2t(const std::array<T, N>& a)
{
return a2t_impl(a, Indices{});
}
int main()
{
auto arr = CreateArray<15>();
auto tu = a2t(arr);
}
但是有这样的编译错误
main.cc:70:32: error: non-type template argument is not a constant expression
return std::make_tuple(Event<a[I]>()...);
^
main.cc:76:10: note: in instantiation of function template specialization
'a2t_impl<std::array<ClassType, 15>, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14>' requested here
return a2t_impl(a, Indices{});
^
main.cc:82:13: note: in instantiation of function template specialization
'a2t<ClassType, 15, std::integer_sequence<unsigned long, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14> >' requested here
auto tu = a2t(arr);
我认为 Array& a 应该是一个模板参数,但也有关于 "conflict on cv-qualification" 的编译错误。
我理解你的问题,因此你希望调用一个 return 的函数,例如,如果你传入 ClassType::kA, ClassType::kB, ClassType::kC, ClassType::kA
,则 std::tuple<EventA, EventB, EventC, EventA>
。这里的挑战如下:函数的return类型(必须在编译时知道)取决于您传递的信息。但是,传递给 constexpr 函数的参数值 不是常量表达式。
考虑到这一点,人们可能会理解编译器的抱怨
main.cc:70:32: error: non-type template argument is not a constant expression
return std::make_tuple(Event<a[I]>()...);
在上下文中
template<typename Array, std::size_t... I>
auto a2t_impl(const Array& a, std::index_sequence<I...>) {
return std::make_tuple(Event<a[I]>()...);
}
A C++17 解决方案 是将参数包装在 constexpr lambda 中:
constexpr auto eventlist = CreateEventList();
constexpr auto tuple_of_events = create_tuple_from_array([=] { return eventlist;});
允许编译器在编译时推断出 return 类型:
namespace detail {
template<class WrappedEventList, size_t... is>
constexpr auto create_tuple_from_array_impl(
WrappedEventList wel, std::index_sequence<is...>
) {
constexpr auto list = wel();
return std::make_tuple(Event<list[is]>{}...);
}
}// detail
template<class WrappedEventList>
constexpr auto create_tuple_from_array(WrappedEventList wel) {
return detail::create_tuple_from_array_impl(
wel, std::make_index_sequence<wel().size()>{}
);
}
Quick and dirty C++17 online demo - 我没有阅读你所有的代码,只是 "made it work"
在 C++14 及以下 中,可能会尝试将枚举作为非类型模板参数传递。
我是 C++ 模板元编程的新手。
我试图从枚举数组中生成专门 class 的 constexpr 元组。
我正在使用 c++14。
这是我的示例代码。
我尝试使用 http://en.cppreference.com/w/cpp/utility/integer_sequence,但是专门的 class 有问题。
#include <iostream>
#include <utility>
#include <tuple>
enum class ClassType{ kA, kB, kC };
template<ClassType Type>
class Event;
template<>
class Event<ClassType::kA>{ void func() { std::cout << "A" << std::endl; } };
template<>
class Event<ClassType::kB>{ void func() { std::cout << "B" << std::endl; } };
template<>
class Event<ClassType::kC>{ void func() { std::cout << "C" << std::endl; } };
class EventList
{
public:
constexpr EventList() : size_(0), list_{ClassType::kA,} {}
ClassType list_[255];
int size_;
};
template <std::size_t Index, EventList&& List>
constexpr auto GetEvent()
{
return Event<List.list_[Index]>();
}
constexpr auto CreateEventList()
{
EventList list;
list.list_[0] = ClassType::kA;
list.list_[1] = ClassType::kB;
list.list_[2] = ClassType::kC;
list.size_ = 3;
return list;
}
int main()
{
constexpr auto eventlist =CreateEventList();
constexpr std::tuple<Event<eventlist.list_[0]>,
Event<eventlist.list_[1]>,
Event<eventlist.list_[2]>
// ... until i==listsize-1
> gentuple;
constexpr auto t = CreateTupleFromArray(eventlist);
}
我也尝试过类似的其他方式。
template<std::size_t SIZE>
constexpr auto CreateArray()
{
std::array<ClassType, SIZE> array = {ClassType::kA,};
for( auto i=0 ; i<SIZE ; ++i )
array[i] = static_cast<ClassType>(i % 3);
return array;
}
template<typename Array, std::size_t... I>
decltype(auto) a2t_impl(const Array& a, std::index_sequence<I...>)
{
return std::make_tuple(Event<a[I]>()...);
}
template<typename T, std::size_t N, typename Indices = std::make_index_sequence<N>>
decltype(auto) a2t(const std::array<T, N>& a)
{
return a2t_impl(a, Indices{});
}
int main()
{
auto arr = CreateArray<15>();
auto tu = a2t(arr);
}
但是有这样的编译错误
main.cc:70:32: error: non-type template argument is not a constant expression
return std::make_tuple(Event<a[I]>()...);
^
main.cc:76:10: note: in instantiation of function template specialization
'a2t_impl<std::array<ClassType, 15>, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14>' requested here
return a2t_impl(a, Indices{});
^
main.cc:82:13: note: in instantiation of function template specialization
'a2t<ClassType, 15, std::integer_sequence<unsigned long, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14> >' requested here
auto tu = a2t(arr);
我认为 Array& a 应该是一个模板参数,但也有关于 "conflict on cv-qualification" 的编译错误。
我理解你的问题,因此你希望调用一个 return 的函数,例如,如果你传入 ClassType::kA, ClassType::kB, ClassType::kC, ClassType::kA
,则 std::tuple<EventA, EventB, EventC, EventA>
。这里的挑战如下:函数的return类型(必须在编译时知道)取决于您传递的信息。但是,传递给 constexpr 函数的参数值 不是常量表达式。
考虑到这一点,人们可能会理解编译器的抱怨
main.cc:70:32: error: non-type template argument is not a constant expression
return std::make_tuple(Event<a[I]>()...);
在上下文中
template<typename Array, std::size_t... I>
auto a2t_impl(const Array& a, std::index_sequence<I...>) {
return std::make_tuple(Event<a[I]>()...);
}
A C++17 解决方案 是将参数包装在 constexpr lambda 中:
constexpr auto eventlist = CreateEventList();
constexpr auto tuple_of_events = create_tuple_from_array([=] { return eventlist;});
允许编译器在编译时推断出 return 类型:
namespace detail {
template<class WrappedEventList, size_t... is>
constexpr auto create_tuple_from_array_impl(
WrappedEventList wel, std::index_sequence<is...>
) {
constexpr auto list = wel();
return std::make_tuple(Event<list[is]>{}...);
}
}// detail
template<class WrappedEventList>
constexpr auto create_tuple_from_array(WrappedEventList wel) {
return detail::create_tuple_from_array_impl(
wel, std::make_index_sequence<wel().size()>{}
);
}
Quick and dirty C++17 online demo - 我没有阅读你所有的代码,只是 "made it work"
在 C++14 及以下 中,可能会尝试将枚举作为非类型模板参数传递。