std::pair抱怨类型不完整

std::pair complains about incomplete type

本文关键字:类型 pair std      更新时间:2023-10-16

如何编译以下代码?

#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,它由于同样的原因无法编译。

typedef本身不是问题所在。写struct foo; typedef std::pair<foo, foo> bar;是完全合法的。有问题

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

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

如果类类型用于需要完全定义的对象类型,或者类类型的完整性是否会影响程序的语义。注意:特别是,如果表达式依赖于类的成员或基类列表模板专业化,类模板专业化隐式生成。例如,删除指向类类型的指针取决于该类是否声明了析构函数,以及指向类类型的指针之间的转换取决于继承所涉及的两个类之间的关系--尾注]

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

尽管编译器在这种情况下不需要实例化std::pair<A, A>,因为移动赋值运算符是完全匹配的(§14.7.1[temp.inst]/p7):

过载解决过程是否能够确定正确的功能要在不实例化类模板定义的情况下调用未指明该实例化是否真的发生。

在将A的整个声明用于另一个声明之前,必须先将其放入。一个前瞻性的参考是不够的。