Search code examples
c++visual-c++initializationinitializer-list

cannot convert from 'initializer list' to template<int>


That's my class:

I'm overloading the operator&& to determine whether an interval has anything in common with a given interval and i'm trying to make an exception for when they dont have anything in common so it will return an interval with two of the same values,which will have to print "EMPTY" within the constructor,but it won't compile due to something with the initializer list. my class: (removed any irrelveant functions)

class Interval
{
public:
    friend ostream & operator<<(ostream &output, const Interval<T> & it) {
        if (&it)
            it.print();
        return output;
    }
    friend istream & operator>>(istream &input, Interval<T> & it) {
        it.enter();
        return input;
    }
    Interval();
    Interval(const T &, const T &);
    Interval<T> operator&&(Interval<T> &it);
    Interval<T> operator||(Interval<T> &it);
    ~Interval();
private:
    T a;
    T b;
    int flag;
};

the function of the overloading &&:

template <class T>
Interval<T> Interval<T>::operator&&(Interval<T> &i1) {
    if (b < i1.a)
        return Interval<T>(i1, i1);
    else if (b == i1.a) 
        return Interval<T>(i1, i1);
    else if (a > i1.b) 
        return Interval<T>(i1, i1);
    else if (a == i1.b) 
        return Interval<T>(i1, i1);
    else {
        if (a<i1.a){
            if (b < i1.b)
                return Interval<T>(i1.a, b);
            else return Interval<T>(i1.a, i1.b);
        }
        if (i1.a < a) {
            if (i1.b < b)
                return Interval<T>(a, i1.b);
            else return Interval<T>(a, b);
        }
    }
}

my constructor:

Interval<T>::Interval(const T &t1, const T &t2) {
    a = t1;
    b = t2;
    if (t1 == t2) {
        cout << "EMPTY";
    }
    flag = 0;
}

and here are the warnings that i get due to that problem.

Error   C2440   '<function-style-cast>': cannot convert from 'initializer list' to 'Interval<int>'  

what is wrong with what i did?


Solution

  • Error   C2440   '<function-style-cast>': cannot convert from 'initializer list'
                     to 'Interval<int>'
    
    no matching constructor for initialization of 'Interval<int>'
           return Interval<T>(i1, i1);
    

    You do not have a constructor taking two Interval<T>'s and i1 is an Interval<T>. You'll have to construct it using two T's (int:s in this case).

    Suggestion: && is usually used for boolean operations where the result is either true or false. If you want to return a ∩ b (the intersection), I think T T::operator&(const T2 &b) const; would be more fitting. Note the const:s! You are not supposed to change any of the values, but return a newly constructed Interval<T>.

    Also, the if(&it) is not necessary. it is a const Interval<T>& (a reference) - and references must always reference something, hence, &it can't return nullptr. If it would have been a const Interval<T>* (a pointer) on the other hand, it could have been nullptr and then the check would have made sense. References are nice that way!

    Another note: You don't have to use the <T> after Interval inside your class definition. Interval means Interval<T> by default. Only if you'd like to mix it with another Interval type would you need to supply the type for it. Like in:

    template<typename T>
    class Interval {
        template<typename U>
        void something(Interval& a, Interval<U>& b) {
            // a is an Interval<T>&
            // b is an Interval<U>&
        }
    };
    

    You also don't need to make the streaming operators friends since they don't access the private members directly. You have your print() and enter() member functions for that.

    Here are more details and suggestions with comments in the code:

    #include <algorithm>  // std::min, std::max
    #include <iostream>
    
    // half-open interval:  [a, b)
    template<typename T>
    class Interval
    {
    public:
        // default constructs an empty interval
        Interval() : 
            Interval({}, {})  // delegating to the below constructor
        {}
    
        Interval(const T& t1, const T& t2) : // <- use the member initializer list
            a{t1},
            b{t2},
            flag{0}
        {
            if(b < a) b = a; // illegal, make it empty
            if(a == b) std::cout << "EMPTY\n";
        }
    
        // itersection
        Interval operator&(const Interval& it) const {
            // Construct the Interval<T> using copy-list-initialization.
            // A return statement with braced-init-list used as the return expression
            // and list-initialization initializes the returned object.
    
            return  {
                        std::max(a, it.a), // get the greatest lower bound
                        std::min(b, it.b)  // get the smallest upper bound
                    };
        }
    
        std::ostream& print(std::ostream& os) const {        
            return os << '[' << a << ',' << b << ')';
        }
    
        std::istream& enter(std::istream& is) {        
            return is >> a >> b;
        }
    
    private:
        T a;
        T b;
        int flag;
    };
    
    // streaming operators do not need to be friends since they use public member functions
    template<typename T>
    std::ostream& operator<<(std::ostream& output, const Interval<T>& it) {
        return it.print(output);
    }
    
    template<typename T>
    std::istream& operator>>(std::istream& input, Interval<T>& it) {
        return it.enter(input);
    }
    
    int main() {
        Interval<int> x(0, 10);
        Interval<int> y(5, 15);
    
        Interval<int> u; // using the new default constructor
        u = x & y;
        std::cout << u << '\n'; // [5,10)
    
        std::cout << (Interval<int>(0,20) & Interval<int>(5,15)) << '\n'; // [5,15)
        std::cout << (Interval<int>(0,10) & Interval<int>(10,20)) << '\n'; // EMPTY [10,10)
        std::cout << (Interval<int>(100,200) & Interval<int>(0,100)) << '\n'; // EMPTY [100,100)
    }