【问题标题】:Template Error: no appropriate default constructor available模板错误:没有合适的默认构造函数可用
【发布时间】:2011-03-07 02:39:00
【问题描述】:

问题是,我不是(知道尝试使用 beatle::beatle 的任何默认构造函数 错误:

1>  ecosystem.cpp
1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\map(172): error C2512: 'beatle::beatle' : no appropriate default constructor available
1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\map(165) : while compiling class template member function 'beatle &std::map<_Kty,_Ty>::operator [](int &&)'
1>          with
1>          [
1>              _Kty=tokenID,
1>              _Ty=beatle
1>          ]
1>          c:\users\zak\documents\visual studio 2010\projects\ascii_sivvure\ascii_sivvure\ecosystem.h(22) : see reference to class template instantiation 'std::map<_Kty,_Ty>' being compiled
1>          with
1>          [
1>              _Kty=tokenID,
1>              _Ty=beatle
1>          ]

去掉不相关内容的代码:

标题:

typedef std::map<tokenID,beatle>    Beatles;

class ecosystem
{
private:
line 22:    Beatles m_Beatles;
};

来源:

ecosystem::ecosystem(): m_output( output() )
{
    Beatles m_Beatles;
}

void ecosystem::populate()
{
    if (m_isMatingSeason && ( random(0,1000) < rateMATING ) )
    {
        beatle babyBeatle = breed();
        m_Beatles[babyBeatle.getTokenID()] = babyBeatle;
        m_field.occupy(babyBeatle.getTokenID(), babyBeatle.getLocation() );
    }
}

我已经尝试使用不同的组合尝试正确定义/声明maps 几个小时。有一次智能感知开始说它想要指向对象的指针:

m_Beatles[babyBeatle.getTokenID()] = babyBeatle;

这让我走上了一条悲伤的道路。

这一切都发生在我第一次(希望是最后一次)重构狂潮之后,距离我能够编译已经一个多星期了......我可能有 40 个小时试图让它再次工作。

【问题讨论】:

    标签: c++ templates constructor


    【解决方案1】:

    std::map&lt;&gt;::operator[] 需要默认构造函数。这是因为它首先在映射中创建一个条目,然后执行您正在调用的 operator=

    如果您绝对想使用 std::map 但不想提供默认构造函数(也许这对您的情况不合逻辑?)您可以使用:

    std::map&lt;&gt;::insert()

    将对象显式插入代码中。这让事情变得有点复杂,因为查找也必须使用 find。

    我刚刚注意到 Adam Rosenfield 已经在评论中发布了此信息,但继续将其作为单独的答案。

    【讨论】:

      【解决方案2】:

      beatle 类是否有默认构造函数?在std::map 上使用operator[] 可以在未使用您提供的键找到条目时在映射中构造一个条目,因此它需要能够创建映射值(此处为beatle)。

      【讨论】:

      • 没有默认 ctor,beatle babyBeatle = breed(); breed() 返回一个 beatle 对象(使用非默认 ctor),我认为我在下一行使用 [] 进行分配。
      【解决方案3】:

      亚当·罗森菲尔德的评论提示更正......

      std::map&lt;&gt;::operator[] 要求值类型有一个公共的默认构造函数:如果你想使用来自std::map&lt;&gt; 的函数,你只需要在class beatle 中有一个。标准说,只要您不调用带有指定默认构造参数的签名的成员函数(见下文),就可以创建非默认构造对象的容器,但这实际上与std::map&lt;&gt;::operator[] 问题不相符使用 T() 尽管没有在签名中提及它。

      20.1.4 - 默认构造 [lib.default.con.req]

      -1- 不需要默认构造函数。某些容器类成员函数签名将默认构造函数指定为默认参数。如果使用默认参数 (dcl.fct.default) 调用其中一个签名,则 T() 必须是明确定义的表达式 (dcl.init)。

      您问这是否意味着您可以在默认构造函数中保留未初始化的成员变量。是的,只要它们不是说可能被operator= 或析构函数删除的指针 - 您需要将它们显式设置为 0/NULL。如果某些成员变量是具有自己默认构造函数的对象,则无论您是否需要它们都可以运行(即即使它们只是设置整数、双精度等),除非编译器时优化能够检测到它们是多余的。

      【讨论】:

      • 难以置信,修复了它。这是什么原因?所以我什至可以不定义所有成员变量,因为我永远不会使用默认构造函数?
      • 不正确。只有operator[] 需要默认构造函数。您可以通过 insertfind 与没有默认构造函数的对象完美地使用映射。
      • 原因是 - 正如 Jeremiah 所说 - 地图执行的一些操作涉及默认构造披头士乐队。您尝试了m_Beatles[babyBeatle.getTokenID()] = babyBeatle;,但这实际上涉及到首先调用map::operator[],它没有找到具有该令牌ID 的现有披头士乐队,因此在使用operator=() 之前它需要默认构造一个立即使用来自babyBeatle 的值复制它。它与编译时分配给变量不同,其中 operator= 有时可以省略为直接就地构造。
      猜你喜欢
      • 1970-01-01
      • 2016-01-22
      • 2016-03-28
      • 2013-08-25
      • 2012-10-10
      • 2014-12-31
      • 2012-12-16
      • 2014-01-31
      相关资源
      最近更新 更多