我想将一系列类存储到元组中,并将此序列声明为另一个类的成员:
template<size_t id> class Foo {};
template<size_t N>
class FooContainer
{
std::tuple<Foo<0>, Foo<1>, ..., Foo<N>> tup; // build this type at compile time ??
};
我试过了:
template<size_t N>
class FooContainer
{
template<size_t... id>
struct FoosImpl {
constexpr FoosImpl(std::index_sequence<id...>) {};
using type = std::tuple<Foo<id>...>;
};
template<size_t N, typename Indices = std::make_index_sequence<N>>
using Foos = decltype(FoosImpl(Indices())::type);
Foos<N> tup;
};
但这并没有编译。海湾合作委员会抱怨:
error: missing template arguments before ‘(’ token using Foos = decltype(FoosImpl(Indices())::type);
我认为编译器不需要指定模板,并且它会从Indices()
中推导出整数序列。但事实似乎并非如此。
答案 0 :(得分:3)
这是一种做你想做的事情的可能方式:
#include <tuple>
template<size_t id> class Foo {};
template <size_t... Idx>
std::tuple<Foo<Idx>...> get_foos(std::index_sequence<Idx...>);
template <size_t N>
using foo_tuple = decltype(get_foos(std::make_index_sequence<N>{}));
template<size_t N>
class FooContainer {
foo_tuple<N> tup;
};
你不能(当前)让编译器推导出类模板参数(正如你需要的FoosImpl
),但是你可以让它推导出函数的模板参数并使用返回类型。
答案 1 :(得分:3)
从您的示例开始,您可以执行此操作:
#include<tuple>
#include<utility>
#include<type_traits>
template<size_t id> class Foo {};
template<size_t N>
struct FooContainer
{
template<size_t... id>
static constexpr std::tuple<Foo<id>...> func(std::index_sequence<id...>) {}
using Foos = decltype(func(std::make_index_sequence<N>()));
Foos foos;
};
int main() {
static_assert(std::is_same<FooContainer<3>::Foos, std::tuple<Foo<0>, Foo<1>, Foo<2>>>::value, "!");
}
答案 2 :(得分:3)
或者您只需使用其他参数到您的FooContainer,默认值为std::index_sequence<0,...,N>
,如:
#include <utility>
#include <tuple>
#include <iostream>
#include <typeinfo>
template<size_t I> class Foo {};
template <size_t N, class = std::make_index_sequence<N>>
struct FooContainer;
template <size_t N, size_t... Is>
struct FooContainer<N, std::index_sequence<Is...>> {
using Foos = std::tuple<Foo<Is>...>;
Foos foos;
};
int main() {
std::cout << typeid(FooContainer<3>{}.foos).name() << std::endl;
}
输出:
$ g++ -std=c++14 example.cc
$ ./a.out
St5tupleII3FooILm0EES0_ILm1EES0_ILm2EEEE
$ c++filt -t St5tupleII3FooILm0EES0_ILm1EES0_ILm2EEEE
std::tuple<Foo<0ul>, Foo<1ul>, Foo<2ul> >
修改:
正如skypjack所提到的,现在可以通过显式传递第二个参数以意外的方式使用我们的FooContainer
类...如果在FooContainer
的第二个参数中传递任意序列是不希望的,则可以保护通过添加static_assert代码如下:
#include <utility>
#include <tuple>
#include <iostream>
#include <typeinfo>
#include <type_traits>
template<size_t I> class Foo {};
template <size_t N, class = std::make_index_sequence<N>>
struct FooContainer;
template <size_t N, size_t... Is>
struct FooContainer<N, std::index_sequence<Is...>> {
static_assert(std::is_same<std::make_index_sequence<N>, std::index_sequence<Is...>>::value, "passed index_sequence was not generated using std::make_index_sequence<N>");
using Foos = std::tuple<Foo<Is>...>;
Foos foos;
};
int main() {
std::cout << typeid(FooContainer<3>{}.foos).name() << std::endl;
}