c++ - constexpr class with array constructor methods -
i trying write compile time class multivariate polynomials (i.e. p(x,y,z) = x^2 + xyz + yz, don't worry mathematics here):
template<int dim, int degree> class polynomial { public: constexpr polynomial(std::array<double,nbofcoeffs(dim,degree)> arr): coeffs(arr) {} constexpr double eval(std::array<double,dim> x); constexpr operator+,-,*,/ ... private: std::array<double,nbofcoeffs(dim,degree)> coeffs; //don't worry "nbofcoeffs" : constexpr , computes @ compile time right number of coefficients. } int main () { polynomial<2,2> p({{1.,1.,1.,1.,1.,1.}}); // p(x,y) = x^2+xy+y^2+x+y+1 double x = p.eval(1.); auto p2 = p*p; }
so far no big problem implement this. however, note ctor can bit cumbersome : how initialize 3rd degree trivariate polynomial p(x,y,z) = xyz ? have
polynomial<3,3> p({{0.,0.,0.,0.,0.,1.,0.,0.,0.,0.}});
with position of non-zero monomial depending on store it. nice if write :
polynomial<3,3> p("xyz"); polynomial<4,3> p("x1x2x3 + x4^2"); //more general
the idea create sort of small dst handle string representation of polynomials.
however, if that, once string parsed, don't know how assign values elements of storing array: must done body of ctor remaining empty (because want constexpr). think of ? possible ? should change array sort of recurring structure (because in case, think really, complex)
an example of how implement luc danton's approach:
#include <cstddef> #include <iostream> namespace polynomials { // it's possible store exponent data member instead template < std::size_t t_id, std::size_t t_exponent = 1 > struct monomial { static constexpr std::size_t id = t_id; static constexpr std::size_t exponent = t_exponent; // it's not possible store coefficient // non-type template parameter (floating-point..) double coefficient; explicit constexpr monomial(double p_coefficient = 1.0) : coefficient{ p_coefficient } {} void print() const { std::cout << coefficient << "x" << t_id << "^" << t_exponent; } }; // create monomial objects (like std::placeholders::_1) constexpr monomial<0> x; constexpr monomial<1> y; constexpr monomial<2> z; constexpr monomial<4> x0; constexpr monomial<5> x1; // ... can use macros produce lot of them.. // multiply arithmetic type (double, int, ..) monomial template < typename t_arithmetic, std::size_t t_id, std::size_t t_exponent0 > constexpr auto operator*(t_arithmetic c, monomial < t_id, t_exponent0 > m0) -> monomial < t_id, t_exponent0 > { return monomial < t_id, t_exponent0 >{c * m0.coefficient}; } // other way 'round template < typename t_arithmetic, std::size_t t_id, std::size_t t_exponent0 > constexpr auto operator*(monomial < t_id, t_exponent0 > m0, t_arithmetic c) -> monomial < t_id, t_exponent0 > { return c * m0; } // multiply 2 monomials same id template < std::size_t t_id, std::size_t t_exponent0, std::size_t t_exponent1 > constexpr auto operator*(monomial < t_id, t_exponent0 > m0, monomial < t_id, t_exponent1 > m1) -> monomial < t_id, t_exponent0 + t_exponent1 > { return monomial<t_id, t_exponent0 + t_exponent1> {m0.coefficient * m1.coefficient}; } // storage type multiple different monomials template < typename... t_monomials > struct polynomial { void print() const {} }; template < typename t_monomial, typename... tt_monomials > struct polynomial < t_monomial, tt_monomials... > : public polynomial < tt_monomials... > { using base = polynomial < tt_monomials... >; t_monomial m; constexpr polynomial(t_monomial p, tt_monomials... pp) : base(pp...) , m{p} {} void print() const { m.print(); std::cout << "*"; base::print(); } }; // multiply 2 monomials polynomial template < std::size_t t_id0, std::size_t t_id1, std::size_t t_exponent0, std::size_t t_exponent1 > constexpr auto operator*( monomial < t_id0, t_exponent0 > m0, monomial < t_id1, t_exponent1 > m1) -> polynomial < monomial<t_id0, t_exponent0>, monomial<t_id1, t_exponent1> > { return {m0, m1}; } // still (and more complicated): // - multiply 2 polynomials // - multiply polynomial , monomial // - addition, subtraction, division (?) etc. }
usage example:
int main() { using namespace polynomials; auto p0 = 1.25*x*x; p0.print(); std::cout << std::endl; auto p1 = p0 * 5*y; p1.print(); std::cout << std::endl; }
Comments
Post a Comment