【问题标题】:Static and non-static member function templates with the same parameter types and requires clause in C++C++ 中具有相同参数类型和 requires 子句的静态和非静态成员函数模板
【发布时间】:2021-12-31 12:19:30
【问题描述】:

不能重载具有相同参数类型的静态和非静态成员函数。但是,如果成员函数是模板并且其中一个具有 requires 子句,那么所有编译器都允许它。但是当调用 both 的成员函数时会出现问题:

struct A {
    static int f(auto) { return 1; }
    int f(auto) requires true { return 2; }
};

int main() {
    [[maybe_unused]] int (A::*y)(int) = &A::f; // ok everywhere (if no below line)
    [[maybe_unused]] int (*x)(int) = &A::f; //ok in GCC and Clang (if no above line)
}

如果main() 中只剩下一个(任何)行,则 GCC 和 Clang 接受该程序。但是当main() 中的两行都存在时,Clang 会打印

error: definition with same mangled name '_ZN1A1fIiEEiT_' as another definition

并且 GCC 报告内部编译器错误。演示:https://gcc.godbolt.org/z/4c1z7fWvx

是否所有编译器都错误地接受具有重载静态和非静态成员函数的struct A 定义?或者他们只是在调用这两个函数时有类似的错误。

【问题讨论】:

  • 这基本上是 stackoverflow.com/questions/70429541/… 的副本,除非我遗漏了什么。
  • 感谢您的参考。在那个问题中,答案是 Clang 是正确的,而 GCC 不是,而这里两者都表现出相同的行为。

标签: c++ static language-lawyer overloading


【解决方案1】:

这太乱了!在浏览标准时,我在[over.over] 中发现了这个更简单的示例:

struct X {
  int f(int);
  static int f(long);
};

int (X::*p1)(int)  = &X::f;     // OK
int    (*p2)(int)  = &X::f;     // error: mismatch
int    (*p3)(long) = &X::f;     // OK

所以我首先尝试了两个有效行,但即使它们也被所有三个编译器拒绝(彼此独立)。这是个问题。

进一步看,关于函数模板的地址,[temp.deduct.funcaddr] 说:

模板参数可以从获取重载集地址时指定的类型推导出来。 如果有目标,则将函数模板的函数类型和目标类型作为P和A的类型,按照[temp.deduct.type]中的描述进行推演。 否则,对类型 P 和 A 的空集进行推导。

[over.over] 中描述了此类目标,在您的示例中属于第一种类型:

(1.1) 正在初始化的对象或引用([dcl.init]、[dcl.init.ref]、[dcl.init.list]),

即使在考虑任何约束之前,在我看来,编译器应该能够在两种情况下识别唯一的候选者,就像在更简单的示例中一样,因为目标具有不同的签名。

【讨论】:

    【解决方案2】:

    根据latest draft of C++20 standard, class.static.mfct#2

    不应有同名和相同参数类型([over.load])的静态和非静态成员函数。

    这里没有例外,requires-clause 的存在是为了区分成员函数,只有相同的名称和相同的参数类型。所以struct A的定义在C++20中是畸形的。

    同一项目在first draft of C++23, class.static.mfct#2中被改写

    不能有具有相同名称、参数类型列表和尾随要求子句([over.load])的静态和非静态成员函数。

    据此,A 的定义已经可以了。即使在 C++20 模式下,GCC、Clang 和 MSVC 看起来也都遵循这个声明。我们观察到的错误发生是因为两个函数的名称相同(保留当前 ABI 几乎无法修复)。

    并且在latest draft of C++, class.static.mfct#2 中删除了对具有相同名称和参数的静态和非静态成员函数的任何限制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-29
      • 1970-01-01
      • 1970-01-01
      • 2014-04-14
      • 2012-04-19
      • 1970-01-01
      • 1970-01-01
      • 2021-09-10
      相关资源
      最近更新 更多