在以下代码(https://wandbox.org/permlink/rA7lnXM6eQR4JhSM)中
#include <type_traits>
template <typename T>
struct Identity : public T {};
class Something {
public:
Something() = default;
Something(const Something&) = delete;
Something(Something&&) = default;
Something& operator=(const Something&) = default;
Something& operator=(Something&&) = default;
template <
typename T,
typename U = std::decay_t<T>,
std::enable_if_t<Identity<
std::is_constructible<U, T&&>>::value>* = nullptr>
explicit Something(T&&) {};
};
int main() {
static_cast<void>(std::is_constructible<Something, const Something&>{});
}
我收到以下错误
error: base class has incomplete type
struct Identity : public T {};
~~~~~~~^
当我在此约束(https://wandbox.org/permlink/MFJCHUzeKnS4yR0d)中使用Identity
删除间接访问时,错误消失了
template <
typename T,
typename U = std::decay_t<T>,
std::enable_if_t<
std::is_constructible<U, T&&>::value>* = nullptr>
explicit Something(T&&) {};
根据我的理解,这里的问题是我们试图实例化std::is_constructible
,然后实例化Something
的构造函数,然后实例化std::is_constructible
,依此类推。
但是,当我尝试不使用Identity
进行编译时,为什么错误消失了?为什么在我使用Identity
时会出错?
答案 0 :(得分:1)
您已经确定存在一个“递归实例化”。没有真正的递归;在“有效”的情况下发生的事情很简单,当考虑构造函数模板以找出从const Something&
构造是否成功时,std::is_constructible<Something, const Something&>
没有成员value
还。 (与普遍看法相反,类C
不需要用C::
来命名成员,但是必须已经声明了命名成员,并且“已经”的确切含义是{{3 }}。
该错误出现在构造函数模板的立即上下文中,因此该模板被忽略。 (在这种情况下,这没有什么区别:(删除的)副本构造函数是更好的匹配,因为它不是模板。)这可以确定丢失的value
是false
,至少与一致,这是第一次拒绝构造函数模板。对于std::is_constructible
本身的非常专业化,这可能违反了a bit murky;考虑到如果我们在控制自身的enable_if
中取消条件,则会随之而来。
您的Identity
遇到相同的错误(或更普遍的相关专业化问题尚未完成)。作为辅助实例的一部分,该错误是无法恢复的。