c++variadic-functionsconstructor-overloading

How to make compiler differentiate f(double...) and f(int, double...)


I am writing a small library for working with polynomials.

The main class is called poly and it contains 4 overloaded constructors.

An object of class poly is a representation of one polynomial.

Full code can be viewed here: https://github.com/IQ8QI/polynomial-lib

In ./test-poly/test-all.cpp I am trying to create an object of class poly:

poly::poly my_poly = poly::poly((double)6.0, -2.0, 4.0);

Constructors of class poly are:

//Create polynomial using just numbers
poly(double values...);

//Create polynomial using vector<double>
poly(vector<double> values);

//Create polynomial with non-zero base
poly(int base, double values...);

//Create polynomial with non-zero base and vector
poly(int base, vector<double> values);

Unfortunately, I am receiving a compilation error:

./test-all.cpp:20:63: error: call of overloaded ‘poly(double, double, double)’ is ambiguous
   20 |         poly::poly my_poly = poly::poly((double)6.0, -2.0, 4.0);
      |                                                               ^
In file included from ./test-all.cpp:3:
././../polynomial-lib/polynomial.hpp:22:17: note: candidate: ‘poly::poly::poly(int, double, ...)’
   22 |                 poly(int base, double values...);
      |                 ^~~~
././../polynomial-lib/polynomial.hpp:16:17: note: candidate: ‘poly::poly::poly(double, ...)’
   16 |                 poly(double values...);
      |                 ^~~~

I understand that the compiler is unable to determine which constructor to use.

I want to stay with solution that there are 4 constructors poly().

To resolve the issue, I can change 2 of the constructors into builder functions, but I don't like it:

//Create polynomial with non-zero base
poly special_poly(int base, double values...){
        poly temp_poly = poly(values...);
        temp_poly.set_base(base);
        return temp_poly;
}

//Create polynomial with non-zero base and vector
poly special_poly(int base, vector<double> values){
        poly temp_poly = poly(values);
        temp_poly.set_base(base);
        return temp_poly;
}

Can it be done without builder functions?


Solution

  • You do not need c varargs when you can use c++ variadic templates which are typesafe. However, you already have a constructor that takes a std::vector, so I see no need for more than a single constructor:

    #include <vector>
    
    
    struct poly{
        std::vector<double> coeffs;
        int base = 0;
        poly(std::vector<double> c,int b = 0) : coeffs(std::move(c)),base(b) {}
    };
    
    int main() {
        poly p1{{1.0,2.0,3.0}};
        poly p2{{1.0,2.0,3.0},0};
    }
    

    I stayed with std::vector passed by value because thats what you asked for. Though, if you never actually need to pass an already constructed vector, but just a list of doubles to the constructor you can change the argument to be a std::initializer_list<double>. If you stay with std::vector consider to pass it as rvalue reference (see below comment by Jan Schultke).