变量初始化无法使用逗号运算符进行编译

Variable initialization fails to compile with comma-operator

本文关键字:运算符 编译 初始化 变量      更新时间:2023-10-16

为什么以下代码中指示的行(在main()中)无法编译?

#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;
}

这称为复制初始化。简而言之,它使用转换构造函数,然后使用复制构造函数来构造inv,而不是像您期望的那样operator =

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

是无效的语法。像Inventory< std::string > inv = "a"这样的东西会首先尝试从"a","b","c","a","c","d","e"创建一个临时Inventory,然后将该临时用作复制构造函数的参数来构造inv。 在这种情况下,永远不会调用operator =

您的第二个版本之所以有效,是因为

Inventory< std::string > inv;

调用默认构造函数,并且

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

对已初始化的对象调用operator =

你的问题是,在一种情况下,逗号是标点符号(和运算符重载不适用),在另一个中,它是一个算子。 不起作用的定义基本上是等效的之:

Inventory<std::string> inv = "a";
Inventory<std::string> "b";
Inventory<std::string> "c";
//  ...

正因为如此,重载operator,总是糟糕的设计;当逗号是一个运算符,当它不是时,就太微妙了。

执行此类操作的常用方法是创建一个相关类收集参数,并将其传递给构造函数:

Inventory<std::string> inv = Collector().add("a").add("b")...;

您还可以重载运算符并使用它,而不是函数 add . 但我没有看到一个可能的运算符(<<,灵感来自ostream?或者你可以重载构造函数和operator() Collector,并写:

Inventory<std::string> inv = Collector("a")("b")...;

然后,您将使用相同的语法进行赋值。 (你真的没有想要一些适合作业的东西,而不是复制的东西建设。