2012-01-14 4 views
4

Основная идея заключается в том, что у меня есть «семейство» классов, которые выполняют одну и ту же идентичную вещь, но несколько иначе. Эта «семья» используется в «высокопроизводительной» петле, поэтому скорость имеет значение. Кроме того, конкретное семейство задается конфигурационным файлом ...Есть ли более эффективный способ структурирования/шаблона C++, чем это?

Проблема в том, что здесь здесь происходит огромное повторение кода. Есть ли лучший способ структурировать это, поэтому мне не нужно писать HP<objx> test и test.loop(bobloblaw) три раза? (На практике этот кусок кода много больше строк, чем 2 ...)

class obj1 { 
public: 
    double f(double x) const { return 1.; } 
}; 

class obj2 { 
public: 
    double f(double x) const { return x; } 
}; 

class obj3 { 
public: 
    double f(double x) const { return x*x; } 
}; 

template <class O> 
class HP { 
private: 
    O obj; 

public: 

    double loop(const vector<double>& x) { 
     double s = 0.; 
     for (auto i : x) s += obj.f(i); 

    return s; 
    } 
}; 

int main() { 
    string config = "bob"; 
    double result = 0; 
    vector<double> bobloblaw; 

    /* Read configuration file to determine which object to use. */ 
    if (config == "obj1") { 
     HP<obj1> test; 
     result = test.loop(bobloblaw); 
    } else if (config == "obj2") { 
     HP<obj2> test; 
     result = test.loop(bobloblaw); 
    } else if (config == "obj3") { 
     HP<obj3> test; 
     result = test.loop(bobloblaw); 
    } 

    return result; 
} 
+0

+1 для bobloblaw – JeremyFromEarth

+0

+1 для арестованных Разработка ссылка. –

ответ

4

Следующая не тестировался, но должен работать:

class obj1 
{ 
public: 
    double f(double x) const { return 1.; } 
}; 

class obj2 
{ 
public: 
    double f(double x) const { return x; } 
}; 

class obj3 
{ 
public: 
    double f(double x) const { return x*x; } 
}; 

class HPbase 
{ 
public: 
    virtual double loop(const vector<double>&) = 0; 
}; 

template <class O> class HP: 
    public HPbase 
{ 
public: 
    double loop(const vector<double>& x) 
    { 
    double s = 0.; 
    for (auto i : x) 
     s += obj.f(i); 
    return s; 
    } 
private: 
    O obj; 
}; 

std::unordered_map<std::string, std::unique_ptr<HPbase>> decode{ 
    {"obj1"}, new HP<obj1>()}, 
    {"obj2"}, new HP<obj2>()}, 
    {"obj3"}, new HP<obj3>()} }; 

int main() 
{ 
    string config = "bob"; 
    double result = 0; 
    vector<double> bobloblaw; 

    /* Read configuration file to determine which object to use. */ 
    result = decode[config].loop(bobloblaw); 
} 

Обратите внимание, что единственным дополнением является базовым классом для HP<> и карту, которая заменяет логику вашего кода if/else.

+0

Спасибо - это идеально и точно тот тип ответа, который я надеялся получить. – notrick

+0

почему unordered_map? Не лучше ли/быстрее использовать std :: map здесь? –

+0

@DavidFeurle: Ну, в этом случае это, вероятно, не имеет значения, потому что есть только один поиск. Однако, как правило, поиск 'std :: map' - это O (log n), поиск wile' std :: unordered_map' - O (1). Поэтому, если у вас достаточно записей, поиск 'unordered_map' будет быстрее. Для нескольких записей я понятия не имею, какой из них быстрее (это может даже зависеть от реализации), но в любом случае это вряд ли будет узким местом. Однако, для нескольких записей, 'std :: map', вероятно, более эффективен с точки зрения памяти. – celtschk

3

вы не могли бы иметь эти 3 класса все быть подклассы ж/того же родителя? main по-прежнему необходимо назначить для тестирования с использованием правого подкласса, но сам тест будет объявлен общим суперклассом.

Недостатком здесь является то, что может быть (возможно, небольшой) удар производительности, поскольку компилятор не знал бы при создании кода для test.loop, какая версия будет использоваться, и, следовательно, ему придется решать во время выполнения.

Альтернативой, которая обошла бы это, было бы написать общий код в виде макроса, который, таким образом, был бы только один раз написан, но расширен в 3 отдельные копии, каждый из которых мог бы оптимизировать компилятор на основе варианта тест используется. Может сделать отладку сукой, но если ваш фокус находится на производительности &, уменьшая избыточность источника (и не столько для объекта), это может быть хорошим компромиссом.

+0

Решение зависит от пользовательского ввода, поэтому оно всегда будет выполняться во время выполнения. –

+0

Какой из них будет использоваться, определяется во время выполнения; но код, который будет выполняться для каждой версии, генерируется во время компиляции, поэтому, если для каждого типа подкласса есть отдельная версия кода, компилятор может лучше оптимизировать каждую версию. –

+0

+1 за предложение использовать макрос, который, несмотря на свою опасность, действительно имеет применение. –

Смежные вопросы