传递概念约束的函数重载

jca*_*cai 11 c++ overloading overload-resolution c++-concepts c++20

以下代码无法编译(Godbolt 链接):

#include <concepts>

template <class Fn>
decltype(auto) g(Fn&& fn) { return fn(); }

template <typename T>
requires(std::integral<T>) int f() { return 0; }

template <typename T>
int f() { return 1; }

int main() {
  f<int>();
  f<void>();
  g(f<int>); // error: invalid initialization of non-const reference of type 'int (&)()'
             // from an rvalue of type '<unresolved overloaded function type>'
  g(f<void>);
}
Run Code Online (Sandbox Code Playgroud)

对我来说,似乎出乎意料的是,调用时重载解析会成功f<int>()(选择受约束的版本作为比不受约束的版本更好的匹配),但作为f<int>参数传递时会失败。

请注意,将无约束版本更改为不相交约束确实可以编译(Godbolt 链接):

#include <concepts>

template <class Fn>
decltype(auto) g(Fn&& fn) { return fn(); }

template <typename T>
requires(std::integral<T>) int f() { return 0; }

template <typename T>
requires(!std::integral<T>) int f() { return 1; }

int main() {
  f<int>();
  f<void>();
  g(f<int>);
  g(f<void>);
}
Run Code Online (Sandbox Code Playgroud)

那么编译器的行为正确吗?如果是这样,这是否是标准中的不一致,或者是否打算以这种方式工作?

Dav*_*ing 5

看来 GCC 和 Clang 都没有完全实现形成约束函数指针的规则:[over.over]/5在选择重载时肯定会考虑约束顺序。尽管它们与不相交约束情况和无约束情况一样相关,但后来对它们进行了一些更改。

\n