Mal*_*ous 9 c++ templates const
在此示例代码中,两个process()函数内的循环是重复的.唯一的区别是一个是const,另一个不是.
有没有办法删除代码重复,这样循环只存在一次?这只是一个例子,但在实际代码中循环非常复杂,因此出于维护原因,我只希望循环存在一次.
#include <iostream>
#include <vector>
typedef unsigned int Item;
typedef std::vector<Item *> Data;
struct ReadOnlyAction {
void action(const Item *i)
{
// Read item, do not modify
std::cout << "Reading item " << *i << "\n";
}
};
struct ModifyAction {
void action(Item *i)
{
// Modify item
std::cout << "Modifying item " << *i << "\n";
(*i)++;
}
};
void process(Data *d, ModifyAction *cb) {
// This loop is actually really complicated, and there are nested loops
// inside it three levels deep, so it should only exist once
for (Data::iterator i = d->begin(); i != d->end(); i++) {
Item *item = *i;
cb->action(item);
}
}
void process(const Data *d, ReadOnlyAction *cb) {
// This is the same loop as above, and so the code should not be duplicated
for (Data::const_iterator i = d->begin(); i != d->end(); i++) {
const Item *item = *i;
cb->action(item);
}
}
void incrementData(Data *d) {
// Here we modify the pointer, and need to loop through it
ModifyAction incrementItem;
process(d, &incrementItem);
}
void saveData(const Data *d) {
// Here we aren't allowed to modify the pointer, but we still need
// to loop through it
ReadOnlyAction printItem;
process(d, &printItem);
}
int main(void)
{
Data d;
// Populate with dummy data for example purposes
unsigned int a = 123;
unsigned int b = 456;
d.push_back(&a);
d.push_back(&b);
incrementData(&d);
saveData(&d);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请注意,这不是一个重复的问题.以下类似的问题和答案是不同的:
如果我尝试在这些答案中给出的解决方案,它不起作用,但看起来像这样:
template <class CB>
void processT(const Data *d, CB *cb) {
// Single loop in only one location
for (Data::const_iterator i = d->begin(); i != d->end(); i++) {
const Item *item = *i;
// Compilation fails on the next line, because const Item* cannot be
// be converted to Item* for the call to ModifyAction::action()
cb->action(item);
}
}
void process(const Data *d, ReadOnlyAction *cb) {
processT(d, cb);
}
void process(Data *d, ModifyAction *cb) {
processT(static_cast<const Data *>(d), cb);
}
Run Code Online (Sandbox Code Playgroud)
这是一个简化的例子,所以如果答案可以集中在问题上(如何从两个process()函数中删除重复的循环)而不是关于设计的评论,那将是非常值得赞赏的 - 如果它删除了设计的改变当然是好的过程中的重复循环.
我假设您关心的是将 a 传递const*给操作。
template<class Arg, class Data, class Action>
static void process_helper(Data *d, Action *cb) {
for (auto i = d->begin(); i != d->end(); i++) {
Arg item = *i;
cb->action(item);
}
}
void process(Data *d, ModifyAction *cb) {
process_helper<Item*>( d, cb );
}
void process(const Data *d, ReadOnlyAction *cb) {
process_helper<Item const*>( d, cb );
}
Run Code Online (Sandbox Code Playgroud)
现在,如果您缺少 C++11,请编写一个特征类:
template<class Data>struct iterator
{ typedef typename Data::iterator iterator; };
template<class Data>struct iterator<const Data>
{ typedef typename Data::const_iterator iterator; };
template<class Arg, class Data, class Action>
static void process_helper(Data *d, Action *cb) {
for (typename iterator<Data>::type i = d->begin(); i != d->end(); i++) {
Arg item = *i;
cb->action(item);
}
}
Run Code Online (Sandbox Code Playgroud)
它可以扩展到多个嵌套循环。