我试图让我的代码在类列表上调用一个方法,我希望能够在编译时配置这个列表。为了使事情更清楚(我希望),这与我目前正在做的大致相同:
SELECT
Item,
Name,
Brand,
Date,
StoreID
FROM
Item
WHERE
Date between '01-01-2017' and '30-01-2017'
OR (Brand = 'Nike' or Brand = 'Jhonson' OR Brand = 'Polo')
SELECT
Item,
Name,
Brand,
Date,
StoreID
FROM
Item
WHERE
Date between '01-01-2017' and '30-01-2017'
AND (Brand = 'Nike' or Brand = 'Jhonson' OR Brand = 'Polo')
基本上,它调用do_something()将A,B和C中的每一个作为模板参数T。
这就是扭曲:我希望能够根据' #ifdef动态启用或禁用A,B和C.我显然可以使用像
这样的东西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());
}
但这导致2 ^ n个语句(如果n是潜在类的数量)。
我的解决方案尝试是为每个要添加到课程列表中的课程T添加一个&#39; AddT&#39;从pack派生的类,匹配参数包&#34; inside&#34;在模板定义中的pack类,然后添加T.以下内容:
#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>;
…
然而,它看起来像是内心的&#39;模板参数(包)&#39;其他&#39;在定义AddC时无法访问,我得到的错误是:
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
我在做一些完全愚蠢的事情吗?有没有更好的方法呢?或者上述问题可以修复吗?我很乐意使用C ++ 14(甚至是C ++ 1z,只要它由合理版本的GCC和clang实现),如果这有任何帮助。
答案 0 :(得分: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
>;
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);
我们将类型包添加到一起以获得我们的答案。
在C ++ 11中,将pack_v<?>
替换为pack<?>{}
。
答案 1 :(得分:5)
如下:
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
>;
然后提供一个帮助类来删除最后一个元素。
答案 2 :(得分:2)
只需一个接一个地添加它们
using ClassList = pack<void
#ifdef USE_A
,A
#endif
#ifdef USE_B
,B
#endif
#ifdef USE_C
,C
#endif
>;
void
是必需的,以便逗号使用第一个非void参数。有两种方法可以处理第一个void
元素。修改do_something
以对T=void
不执行任何操作,或使用帮助template
将其删除,如Yakk's answer中所述。