我想从图书馆请求一系列数据,这需要我指定两种类型:
class a;
class b;
class c;
template<typename A, typename B> void get() {....}
void get_all() {
get<a,a>()
get<a,b>()
get<a,c>()
get<b,a>()
get<b,b>()
// etc...
}
我想为一组类(大约 10 种不同的变体)的每个组合调用 get 函数 - 这意味着大约 100 次不同的调用。我不想手动编写所有这些 get() 调用的代码。
有什么方法可以自动生成这些调用吗?我想我可以使用预处理器宏,但我很好奇是否有办法生成这样的组合列表,给定 a、b、c、d... 通过使用模板代码。
编辑:小问题:事实上,这一切都在一个成员函数中。
template<typename A, typename B>
void Getter::get()
{
auto assn = fMemberObject->RetrieveAllDataOfType<association<A,B>();
.. do stuff with assn ...
}
void Getter::get_all() {
get<a,a>();
}
因此,代码需要处理传递 this
连同模板。
此外,如果可能的话,C++11 可能是我想要插入该语言的极限......
编辑 2:
结果我想避免重复的情况 <a,a>
和 <b,b>
...
最佳答案
当对解决模板元编程问题有疑问时,考虑一下如何在正常编程中做到这一点会有所帮助。在这种情况下,我们想要这样的东西:
for a in type_list:
for b in type_list:
foo(a,b)
那么,让我们将其直接翻译成 C++。我们需要一种表示类型和类型列表的方法:
template <class T> struct tag { };
template <class... Ts> struct type_list { };
我们需要一种遍历类型列表并为每种类型做一些事情的方法。我们将其称为函数调用。在 C++17 中(在 C++14 及更低版本中,您可以使用 swallow/expander 技巧在每个 f
上调用 tag<Ts>
):
template <class... Ts, class F>
void for_each(type_list<Ts...>, F f) {
(f(tag<Ts>{}), ...);
}
那是……基本上就是这样。我们需要一个实际调用的函数、一个类型列表和代码:
template <class X, class Y>
void foo(tag<X>, tag<Y> ) {
std::cout << __PRETTY_FUNCTION__ << '\n'; // or something more meaningful
}
int main() {
type_list<a, b, c> types;
for_each(types, [=](auto x){
for_each(types, [=](auto y){
foo(x, y);
});});
}
C++11 version ,某种程度上展示了通用 lambda 的强大功能。
基于希望类型不一样的更新,这样也很容易更新。我们可以在 tag
中添加一个相等运算符:
template <class T, class U>
constexpr std::integral_constant<bool, std::is_same<T,U>::value>
operator==(tag<T>, tag<U> ) { return {}; }
template <class T, class U>
constexpr std::integral_constant<bool, !std::is_same<T,U>::value>
operator!=(tag<T>, tag<U> ) { return {}; }
请注意,我们不会返回 bool
,我们将返回一个在类型系统中对结果进行编码的类型。然后我们可以自然地使用它:
for_each(types, [=](auto x){
for_each(types, [=](auto y){
if constexpr (x != y) {
foo(x, y);
}
});});
foo(x,y)
仅当两种标记类型不同时才会实例化。
关于C++ 组合模板扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44297950/