【问题标题】:Using a level of indirection in a template SFINAE constraint causes a hard error在模板 SFINAE 约束中使用间接级别会导致硬错误
【发布时间】:2019-05-04 18:36:34
【问题描述】:

在以下代码中(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时会出错?

【问题讨论】:

  • is_constructible_v 从 C++17 开始,只是为了简化代码
  • 在我脑海中浮现:std::is_constructible 不继承自它的任何一个参数,因此它的操作约束与您的 Identity 类不同。

标签: c++ templates language-lawyer c++17 sfinae


【解决方案1】:

您已经知道存在“递归实例化”。没有真正的递归;在“有效”的情况下发生的情况很简单,当考虑构造函数模板以找出从 const Something&amp; 构造是否会成功时,std::is_constructible&lt;Something, const Something&amp;&gt; 没有成员 value尚未。 (与流行的看法相反,C 类不需要完整才能用 C:: 命名成员,但命名的成员必须已经声明,“已经”的确切含义是 a bit murky。)

该错误在构造函数模板的即时上下文中,因此模板被静默忽略。 (这在这种情况下没有区别:(删除的)复制构造函数是更好的匹配,因为它不是模板。)这确定了缺少的 valuefalse,这至少是 一致的 第一次拒绝了构造函数模板。这可能违反了[meta.rqmts]/5std::is_constructible 本身的专门化;考虑一下,如果我们否定控制自身的enable_if 中的条件,就会产生欢闹。

您的Identity 遇到相同的错误(或相关专业化尚未完成的更一般问题)。作为辅助实例化的一部分,该错误是不可恢复的。

【讨论】:

  • 这是否也意味着[meta.unary.prop]/Table 47,关于std::is_constructible的模板参数的完整性前提条件,即"T和所有类型在参数包Args 应为完整类型”,是否违反(在两个示例中)?
  • @dfri:不——默认模板参数只有在需要时才会实例化,此时 Something 已完成。
  • 不确定我是否遵循,如果我不从它继承并直接使用 value 成员,为什么错误仍然存​​在 - wandbox.org/permlink/i6LGLny3KpuAKslY
  • @Curious:我过分强调了完整性问题,抱歉。 value 的查找失败与继承 while is_constructible 被实例化一样多,并且在直接上下文之外也一样多。我添加了更多解释性细节,并将重新措辞以避免混淆完整性。
猜你喜欢
  • 1970-01-01
  • 2015-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多