炸鱼薯*_*德里克 5 c++ templates template-specialization template-meta-programming c++11
我有一个带有整数参数的模板,但基本模板是这样禁用的static_assert().(我只想要一些特定的表格;我希望除了某些参数外,任何传递给模板的参数都是禁止的)
template<ItemID item_id> struct ItemTemplate{
static_assert(item_id == -1,"Cann't use unspecialized ItemTemplate!");
static ItemID id{ std::numeric_limits<ItemID>::max() };
//...
};
Run Code Online (Sandbox Code Playgroud)
我也有这个模板的几个专业化表格(我经常添加或删除其中的一些)
template<> struct ItemTemplate<1>{
static constexpr ItemID id{1};
//..
};
template<> struct ItemTemplate<2>{
static constexpr ItemID id{2};
//...
};
Run Code Online (Sandbox Code Playgroud)
现在我想创建一个std::tuple仅由所有可用类型初始化的.所以在上面的例子中,ItemTemplate<1>和ItemTemplate<2>,而不是ItemTemplate<3>和其他非专业类型.我该如何实现这一目标?
我看到了一种方法,但前提是您忘记了static_assert()拒绝方式并仅定义ItemTemplate.
以下是一个简化的示例,其中我仅定义了一些特殊化foo,并且foo通用结构保持未定义。
template <std::size_t>
struct foo;
template <> struct foo<2U> {};
template <> struct foo<3U> {};
template <> struct foo<5U> {};
template <> struct foo<7U> {};
Run Code Online (Sandbox Code Playgroud)
现在您需要一些东西来检测类型是否已定义;例如,以下
template <typename T, std::size_t = sizeof(T)>
std::true_type existH (int);
template <typename>
std::false_type existH (long);
template <typename T>
using exist = decltype(existH<T>(0));
Run Code Online (Sandbox Code Playgroud)
即:从exist<foo<0>>::value你得到false和从exist<foo<2>>::value你得到true。
foo现在您需要一个从下限(例如零)到上限定义的专业化索引列表(可用的编译时间) 。
您可以通过以下方式获取它
template <std::size_t I, std::size_t topI, typename,
bool = (I == topI) || exist<foo<I>>::value>
struct fooIndexList;
template <std::size_t topI, std::size_t ... Ixs>
struct fooIndexList<topI, topI, std::index_sequence<Ixs...>, true>
{ using type = std::index_sequence<Ixs...>; };
template <std::size_t I, std::size_t topI, std::size_t ... Ixs>
struct fooIndexList<I, topI, std::index_sequence<Ixs...>, true>
{ using type = typename fooIndexList<I+1U, topI,
std::index_sequence<Ixs..., I>>::type; };
template <std::size_t I, std::size_t topI, std::size_t ... Ixs>
struct fooIndexList<I, topI, std::index_sequence<Ixs...>, false>
{ using type = typename fooIndexList<I+1U, topI,
std::index_sequence<Ixs...>>::type; };
Run Code Online (Sandbox Code Playgroud)
使用fooIndexList,获得std::tuple具有所有foo定义(从零到上限)的 a 非常简单:
template <std::size_t ... Idx>
constexpr auto makeFooTupleH (std::index_sequence<Idx...> const &)
{ return std::make_tuple( foo<Idx>{} ... ); }
constexpr auto makeFooTuple ()
{ return makeFooTupleH(
typename fooIndexList<0U, 100U, std::index_sequence<>>::type {}); }
Run Code Online (Sandbox Code Playgroud)
在示例中,上限为100但可以是 的模板参数makeFooTuple()。
以下是完整的编译示例
#include <tuple>
#include <utility>
#include <iostream>
#include <type_traits>
template <typename T, std::size_t = sizeof(T)>
std::true_type existH (int);
template <typename>
std::false_type existH (long);
template <typename T>
using exist = decltype(existH<T>(0));
template <std::size_t>
struct foo;
template <> struct foo<2U> {};
template <> struct foo<3U> {};
template <> struct foo<5U> {};
template <> struct foo<7U> {};
template <std::size_t I, std::size_t topI, typename,
bool = (I == topI) || exist<foo<I>>::value>
struct fooIndexList;
template <std::size_t topI, std::size_t ... Ixs>
struct fooIndexList<topI, topI, std::index_sequence<Ixs...>, true>
{ using type = std::index_sequence<Ixs...>; };
template <std::size_t I, std::size_t topI, std::size_t ... Ixs>
struct fooIndexList<I, topI, std::index_sequence<Ixs...>, true>
{ using type = typename fooIndexList<I+1U, topI,
std::index_sequence<Ixs..., I>>::type; };
template <std::size_t I, std::size_t topI, std::size_t ... Ixs>
struct fooIndexList<I, topI, std::index_sequence<Ixs...>, false>
{ using type = typename fooIndexList<I+1U, topI,
std::index_sequence<Ixs...>>::type; };
template <std::size_t ... Idx>
constexpr auto makeFooTupleH (std::index_sequence<Idx...> const &)
{ return std::make_tuple( foo<Idx>{} ... ); }
constexpr auto makeFooTuple ()
{ return makeFooTupleH(
typename fooIndexList<0U, 100U, std::index_sequence<>>::type {}); }
int main ()
{
auto ft = makeFooTuple();
static_assert( std::is_same<decltype(ft),
std::tuple<foo<2U>, foo<3U>, foo<5U>, foo<7U>>>{}, "!");
}
Run Code Online (Sandbox Code Playgroud)
限制:
foo仅当未定义泛型时此解决方案才有效makeFooTuple()不能太大,因为fooIndexList是递归的,因此受到编译器递归限制的限制;您可以绕过此限制,但需要模式代码。