我正在尝试编写一个模板函数,该函数在一些结构体集合中的用户指定字段上进行迭代。例如,我要编写以下C ++:
struct Example {
int a;
bool b;
};
template<std::function<Field& (Class)> GetField, typename Field, typename Class>
void myFunc(std::iterator<Class> begin, size_t const length) {
cout << length << endl;
for (size_t i{ 0 }; i < length; ++begin, ++i) {
Field const &field{ GetField(*begin) };
// Forward field to some other template function
anotherTemplateFunction<Field>(field);
}
}
void main() {
Example exArray[]{ {5, true}, {8, false} };
std::list<Example> exList{ exArray, exArray + _countof(exArray) }
// Examples of how I would like to call myFunc...
myFunc<Example::a>(exArray, _countof(exArray));
myFunc<Example::b>(exList.begin(), exList.size());
}
以上方法不起作用,但希望其意图是明确的。如何编写myFunc模板方法以在每个迭代项目的某些字段上完成通用迭代?另外,如果有某种方法(在Boost或标准库中)直接在exArray[i].a
上创建迭代器,那也是可以接受的。
答案 0 :(得分:3)
我通常使用的是这样的:
void main() {
std::array<Example, 2> exArray{ {5, true}, {8, false} };
std::list<Example> exList{ exArray.begin(), exArray.end() };
auto access_a = [](Example& e)->int&{ return e.a;};
auto access_b = [](Example& e)->bool&{ return e.b;};
myFunc(exArray.begin(), exArray.end(), access_a);
myFunc(exList.begin(), exList.end(), access_b);
}
template<class ForwardIt, class Accessor>
void myFunc(ForwardIt begin,ForwardIt end, Accessor accessor) {
cout << end - begin << endl;
for (auto it = begin; it != end; it++) {
// Forward field to some other template function
anotherTemplateFunction(accessor(*it));
}
}
请注意我是如何使用std::array
而不是原始的c样式数组的。
如果您有权使用c ++ 11编译器,则始终应首选std::array
(或std::vector
)而不是原始c数组。 ES.27
为了需要更少的样板代码,请考虑使用一些解决此“迭代类字段”问题的序列化库,例如boost serialization或magic get。
答案 1 :(得分:2)
如果您知道指向成员语法等的指针,这很简单。不幸的是很少使用,是该语言的一种深奥特征:
template <class T> void foo(T);
template <auto Field, class It>
auto myFunc(It begin, It end)
{
for (; begin != end; ++begin)
{
foo((*begin).*Field);
}
}
int main()
{
std::vector<Example> v{{5, true}, {8, false}};
myFunc<&Example::a>(v.begin(), v.end()); // will call foo<int>(5) , foo<int>(8)
myFunc<&Example::b>(v.begin(), v.end()); // will call foo<bool>(true) , foo<bool>(false)
}
对于template <auto Field
,您需要C ++ 17。
对于C ++ 11,语法更为冗长:
template <class T, class F, F T::* Field, class It>
void myFunc(It begin, It end)
{ /* same */ }
int main()
{
std::vector<Example> v{{5, true}, {8, false}};
myFunc<Example, int, &Example::a>(v.begin(), v.end()); // will call foo<int>(5) , foo<int>(8)
myFunc<Example, bool, &Example::b>(v.begin(), v.end()); // will call foo<bool>(true) , foo<bool>(false)
}
您的问题有点过时,但是我不明白为什么您将std::list
的初始化复杂化了。在C ++中,您选择的第一个容器应该是std::vector
。
也没有std::iterator