Luk*_*rth 2 c++ templates variadic-templates c++11 c++14
我试图让我的代码调用类列表上的方法,我希望能够在编译时配置此列表.为了使问题更清楚(我希望),这与我目前正在做的大致相同:
template <class...> class pack {};
class A {
public:
static void foo() {};
};
class B {
public:
static void foo() {};
};
class C {
public:
static void foo() {};
};
using ClassList = pack<A, B, C>;
template<class T, class ...Remaining>
void do_something(pack<T, Remaining...>) {
// do something with T
T::foo();
do_something(pack<Remaining...>());
}
void do_something(pack<>) {
// do nothing, recursion ends
}
int main() {
do_something(ClassList());
}
Run Code Online (Sandbox Code Playgroud)
基本上,它调用do_something()将A,B和C中的每一个作为模板参数T.
这是扭曲:我希望能够根据'#ifdef'动态启用或禁用A,B和C. 我显然可以使用类似的东西
#if defined(USE_A) && defined (USE_B) && defined (USE_C)
using ClassList = pack<A, B, C>;
#elif defined(USE_A) && defined (USE_B)
using ClassList = pack<A, B>;
…
Run Code Online (Sandbox Code Playgroud)
但这导致2 ^ n个语句(如果n是潜在类的数量).
我的解决方案尝试是为每个要添加到类列表中的类T添加一个派生自派生的'AddT'类,在其模板定义中匹配包类的"内部"参数包,然后添加T.有点像:
using BaseClassList = pack<A, B>;
#ifdef USE_C
template <template <class ...Others> class oldpack>
class AddC : public pack<C, Others...> {};
using ClassesWithC = AddC<BaseClassList>;
#else
using ClassesWithC = BaseClassList;
#endif
Run Code Online (Sandbox Code Playgroud)
但是,在定义AddC时看起来"内部"模板参数(pack)'Others'是不可访问的,我得到的错误是:
error: 'Others' was not declared in this scope
Run Code Online (Sandbox Code Playgroud)
我在做一些完全愚蠢的事吗?有没有更好的方法呢?或者上述问题可以修复吗?我很乐意使用C++ 14(甚至是C++ 1z,只要它是由合理版本的GCC和clang实现的),如果这有任何帮助.
Yak*_*ont 11
利用C++的空白灵活性并分别检查每个.
template<class, class...Ts>
using pack_helper = pack<Ts...>;
using ClassList = pack_helper<void
#ifdef USE_A
,A
#endif
#ifdef USE_B
,B
#endif
#ifdef USE_C
,C
#endif
>;
Run Code Online (Sandbox Code Playgroud)
pack_helper丢弃它的第一种类型,然后生成pack其余的.我们通过void它.
我们这样做是因为每个其他包元素都可以以逗号开头,包括第一个.
但这并不像它可能那么有趣.
template<class...>struct pack{using type=pack; constexpr pack(){}};
template<class...Ts>constexpr pack<Ts...> pack_v{};
template<class...Ts, class...Us>
constexpr pack<Ts...,Us...>
operator+( pack<Ts...>, pack<Us...> )
{ return {}; }
constexpr auto Classes = pack_v<>
#ifdef USE_A
+pack_v<A>
#endif
#ifdef USE_B
+pack_v<B>
#endif
#ifdef USE_C
+pack_v<C>
#endif
;
using ClassList = decltype(Classes);
Run Code Online (Sandbox Code Playgroud)
我们在其中添加类型包以获得我们的答案.
在C++ 11中,替换pack_v<?>为pack<?>{}.
怎么样的:
using ClassList = pack<
#if defined(USE_A)
A,
#endif
#if defined (USE_B)
B,
#endif
#if defined (USE_C)
C,
#endif
struct dummy // For comma
>;
Run Code Online (Sandbox Code Playgroud)
然后提供一个帮助类来删除最后一个元素.