如何编译以下代码?
#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:B型模拟boost :: recursive_wrapper,由于同样的原因无法编译。
答案 0 :(得分:8)
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):
如果重载解析过程可以确定正确的功能 如果没有实例化类模板定义就调用它 未指定实例化是否实际发生。
答案 1 :(得分:2)
在您在另一个声明中使用它之前,您必须实际输入A的整个声明。前瞻性参考不够。