【问题标题】:std::pair complains about incomplete typestd::pair 抱怨类型不完整
【发布时间】:2014-09-19 01:53:58
【问题描述】:

如何编译下面的代码?

#include <type_traits>
#include <utility>

struct A;

template<typename T>
struct B{
    T* p;

    B& operator=(B&&);
    B& operator=(T&&);
};

int main(){
    //typedef B<A> type;// fine
    typedef B<std::pair<A, A>> type;// error

    noexcept(std::declval<type&>() = std::declval<type>());

    return 0;
}

PS:Type B 模拟 boost::recursive_wrapper,同样原因编译失败。

【问题讨论】:

  • 17.6.4.8/2 特别是,在以下情况下效果未定义: ... --如果使用不完整类型 (3.9) 作为模板参数实例化模板组件时,除非该组件特别允许。
  • @IgorTandetnik typedef 本身不应该实例化std::pair&lt;A, A&gt;。
  • 是否可以选择将B 设为模板并将A 设为模板参数?
  • @jxh typedef 不是需要完整类型的上下文。
  • @5gon12eder 我编辑代码以使用模板。

标签: c++ c++11 boost


【解决方案1】:

typedef 本身不是问题。写struct foo; typedef std::pair&lt;foo, foo&gt; bar; 是完全合法的。问题出在

noexcept(std::declval<type&>() = std::declval<type>());

这需要编译器为operator= 执行重载解析。作为重载解决方案的一部分,它必须寻找从B&amp;&amp; 到std::pair&lt;A, A&gt;&amp;&amp; 的可能转换,这需要实例化std::pair&lt;A,A&gt; (§14.7.1 [temp.inst]/p6):

一个类模板特化被隐式实例化,如果 类类型在需要完全定义的上下文中使用 对象类型或类类型的完整性可能会影响 程序的语义。 [ 注意:特别是,如果 表达式依赖于类的成员或基类列表 模板特化,类模板特化是 隐式生成。例如,删除指向类类型的指针 取决于类是否声明了析构函数,并且 指向类类型的指针之间的转换取决于继承 所涉及的两个类之间的关系。 —尾注 ]

...并且,根据 §17.6.4.8 [res.on.functions]/p2,此实例化会导致未定义的行为。

尽管编译器不需要在此上下文中实例化 std::pair&lt;A, A&gt;,因为移动赋值运算符是完全匹配的(§14.7.1 [temp.inst]/p7):

如果重载解析过程可以确定正确的函数 在不实例化类模板定义的情况下调用,它是 未指定该实例化是否实际发生。

【讨论】:

  • 我想你明白了。那么如何绕过这个问题呢?你可以直接学习 boost::recursive_wrapper。
  • @user1535111 我无法理解这里的一些编译器行为。所以I've asked a question.
【解决方案2】:

您必须先实际放入 A 的整个声明,然后才能在另一个声明中使用它。前向引用是不够的。

【讨论】:

  • 问题是有时不可能做到这一点。这是 boost::recursive_wrapper 的值。
猜你喜欢
  • 2016-09-10
  • 1970-01-01
  • 2017-04-05
  • 2015-07-02
  • 1970-01-01
  • 2014-07-21
  • 2017-12-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多