Search code examples
c++variable-initialization

Variable initialization fails to compile with comma-operator


Why does the line indicated ( in main() ) in the following code not compile?

#include <iostream>
#include <string>
#include <map>

template< typename _T > struct Inventory : public std::map< _T, int >
{
    bool getat(int i, _T &t, int &n)
    {
        if ((i < 0) || (i >= (int)this->size())) return false;
        int c=0;
        typename std::map< _T, int >::iterator it = this->begin();

        while ((c < i) && (it != this->end())) { c++; it++; }
        t = (*it).first;
        n = (*it).second;
        return true;
    }
    Inventory &operator=(_T t) { (*this)[t]++; return *this; }
    Inventory &operator,(_T t) { return operator=(t); }
};

int main()
{
    int i=0, quantity;
    std::string item;

    //***Fails to compile:***
    //Inventory< std::string > inv = "a","b","c","a","c","d","e";  

    Inventory< std::string > inv;
    inv = "a","b","c","a","c","d","e";    //but this is fine
    inv = "e","f";

    while (i < (int)inv.size())
    {
        if (inv.getat(i, item, quantity)) 
                std::cout << i << ": " << item << " -> " << quantity << "\n";
        i++;
    }
    return 0;
}

Solution

  • That's called copy-initialization. In short, it uses the conversion constructor and then the copy constructor to construct inv, not operator = as you expect.

    Inventory< std::string > inv = "a","b","c","a","c","d","e";  
    

    is invalid syntax. Something like Inventory< std::string > inv = "a" would first attempt to create a temporary Inventory from "a","b","c","a","c","d","e" and then use that temporary as argument to a copy constructor to construct inv. operator = is never called in this case.

    Your second version works because

    Inventory< std::string > inv;
    

    calls the default constructor, and

    inv = "a","b","c","a","c","d","e"; 
    

    calls operator = on an already initialized object.