Создание простого класса выражений с пакетами параметров и кортежами - PullRequest
0 голосов
/ 04 мая 2019

Я пытаюсь создать класс выражений, который принимает классы, производные от «DMGType», и может суммировать их вместе, например:

 CritDamage+4*AllDamage+MeleeDamage

, а затем вычисляет его значение с помощью параметра «build»Например, если build "Mage" = 0 в терминах программирования, результат должен быть:

CritDamage(0)+4*AllDamage(0)+MeleeDamage(0) = 0.5+4*1+0

Вот моя попытка:

#include<iostream>
#include<tuple>
#include<cstddef>
template <typename ValueType>
class DMGType {
public:
    ValueType coeff=0;
    virtual ValueType getExpo(std::size_t build) = 0;
    DMGType<ValueType>& sum(DMGType<ValueType> const& dmg) {
        this->coeff+=dmg.coeff;
        return this;
    }
};

template<typename ValueType, class... DMGTypesDerived>
class Expression {
public:
    std::tuple<DMGTypesDerived...> parameters;
    void sum(DMGType<ValueType> const& dmg) {
        std::get<dmg>(parameters).sum(dmg);
    }
    ValueType result{0};
        //desired result: return std::get<DMGTypes1>(parameters).getExpo(build) + ... + std::get<DMGTypesLast>.getExpo(build);
        result+=std::get<DMGTypesDerived>(parameters).getExpo(build) + ...;
        return result;
};

class CritDamage: public DMGType<double> {
public:
    double getExpo(std::size_t build) {
        return build+1;
    }
};

int main() {
    Expression<double, CritDamage> test;
    CritDamage crit;
    crit.coeff=1;
    test.sum(crit);
    std::cout<<test.getExpo(0);
}

Ошибки, которые я получаю:

prog.cc:24:69: error: expected ';' before '+' token
   24 |         result+=std::get<DMGTypesDerived>(parameters).getExpo(build) + ...;
      |                                                                     ^~
      |                                                                     ;
prog.cc:24:15: error: parameter packs not expanded with '...':
   24 |         result+=std::get<DMGTypesDerived>(parameters).getExpo(build) + ...;
prog.cc:24:15: note:         'DMGTypesDerived'

Я открыт для лямбда-функций, std :: apply, invoke, прямого расширения / сворачивания, но все, что я пробовал до сих пор, дало мне некоторые ошибки, так как я не до конца понимаю эти концепции.

Мне также известны проблемы, которые могут возникнуть из-за функции Expression :: sum, которая не будет обрабатывать полиморфизм, и я был бы благодарен за помощь и по этому вопросу.

Решение

#include<iostream>
#include<tuple>
#include<cstddef>
template <typename ValueType>
class DMGType {
public:
    DMGType(ValueType v) 
    :coeff(v) {};
    DMGType() 
    :coeff(0) {};
    ValueType coeff=0;
    virtual ValueType getExpo(std::size_t build) = 0;
    void sum(DMGType<ValueType> const& dmg) {
        this->coeff+=dmg.coeff;
    }
};

template<typename ValueType, class... DMGTypesDerived>
class Expression {
public:
    std::tuple<DMGTypesDerived...> parameters;
    template<class DerivedClass>
    void sum(DerivedClass const& dmg) {
        std::get<DerivedClass>(parameters).sum(dmg);
    }
    ValueType getExpo(std::size_t build) {
        return (std::get<DMGTypesDerived>(parameters).getExpo(build) + ...);
    }
};

class CritDamage: public DMGType<double> {
public:
    double coeff=0;
    CritDamage(double v) :coeff(v) {}
    CritDamage() :coeff(0) {}
    double getExpo(std::size_t build) {
        return build+1;
    }
};

class MeleeDamage: public DMGType<double> {
public:
    double coeff=0;
    MeleeDamage(double v) :coeff(v) {}
    MeleeDamage() :coeff(0) {}
    double getExpo(std::size_t build) {
        return build*2+1;
    }
};

int main() {
    Expression<double, CritDamage, MeleeDamage> test;
    CritDamage crit(1);
    test.sum(crit);
    MeleeDamage melee(2);
    melee.sum(crit);
    std::cout<<test.getExpo(1);
}

Ответы [ 2 ]

1 голос
/ 04 мая 2019

Вам не хватает скобок в выражении сгиба. Попробуйте это:

ValueType getExpo(std::size_t build) {
    ValueType result{0};
    result += (std::get<DMGTypesDerived>(parameters).getExpo(build) + ...);
    return result;
}

На самом деле, вы можете пропустить result и просто сделать это:

ValueType getExpo(std::size_t build) {
    return (std::get<DMGTypesDerived>(parameters).getExpo(build) + ...);
}
1 голос
/ 04 мая 2019

Вы можете создать список инициализаторов на лету и суммировать результат:

ValueType getExpo(std::size_t build) {
    ValueType result{0};
    //desired result: return std::get<DMGTypes1>(parameters).getExpo(build) + ... + std::get<DMGTypesLast>.getExpo(build);
    for (auto s : { std::get<DMGTypesDerived>(parameters).getExpo(build)...} )
        result += s;
    return result;
}
...