模板化类的格式错误的非模板化方法的实例化

Instantiation of ill-formed non-templated method of a templated class

本文关键字:方法 实例化 格式 错误      更新时间:2023-10-16

我正在研究两阶段名称查找。一个非常合乎逻辑的解释表明,其主要原因之一是遵循了c++ 尽可能早地捕获错误的哲学

我的问题是,为什么非模板方法不遵循这一哲学。与其检查方法何时以及是否被调用,为什么不在模板化类实例化的阶段2中检查所有非模板化的方法呢?

例如:

template <class T>
struct X {
  auto foo() // non-templated (important)
  {
    T t{};
    return t.non_existing();
  }
};
int main()
{
  X<int> x; // (1) this compiles OK.
  // somewhere is a galaxy far far away,
  // maybe deep inside some unrelated code
  x.foo();  // (2) the error is here
}

如果你从不写(2)程序编译和运行没有任何问题,尽管foo对于实例化的X<int>是非法的。

我认为(1)行应该产生错误,不管你是否调用过foo

在编写模板化类时,这可以让错误从缝隙中溜走,直到您最终调用有问题的方法(2),而不是在实例化模板化类(1)时获得错误。

也完整性检查:是代码有效,如果我实例化X<int>(1),但从未调用X<int>::foo (2)?或者是"格式错误,不需要诊断"之类的问题?如果是后者,则更有理由更早地捕获错误。

代码有效。

这个特性被设计成允许像std::vector这样的东西可以简单地写成operator<operator==

该操作符将尝试在其元素上盲目调用<==。如果它无效,一旦在包装vector上调用<==,它将无法编译。

但是如果你从来没有这样做过,vector也会工作得很好。

现代c++会建议使用SFINAE条件方法技术或c++ 20要求子句,所以vector只有 ==<,如果它是一个有效的操作。在设计vector的时候,这些技术都还不成熟,而拥有模板类中无效方法的能力是一个重要的特性。

在无效代码的早期失败之上,让==有条件地存在允许包装代码检测==是否可以安全调用:古老的技术不允许这种自省。我不得不编写专门针对标准容器模板的自定义特征,以检测<在至少一种情况下是否可以安全调用。