如何在调用其他函数的const和非const函数之间重用代码

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)

请注意,这不是一个重复的问题.以下类似的问题和答案是不同的:

  • 123758 - 仅涵盖返回值的简单函数,而此函数调用其他函数,因此在此处给出的解决方案不适用于此问题
  • 23809745 - 同样的问题,只涵盖返回值的简单函数,答案不适用于此问题

如果我尝试在这些答案中给出的解决方案,它不起作用,但看起来像这样:

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()函数中删除重复的循环)而不是关于设计的评论,那将是非常值得赞赏的 - 如果它删除了设计的改变当然是好的过程中的重复循环.

Yak*_*ont 1

我假设您关心的是将 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)

它可以扩展到多个嵌套循环。