应该热切还是懒惰地评估 C++ 约束?

Should c++ constraints be evaluated eagerly or lazily?

这个问题的主要目的是引起社区对不适用于 clang 的 libstdc++ 范围的关注:https://bugs.llvm.org/show_bug.cgi?id=46746

Avi Kivity 建议这是一个 gcc 错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97120

但随后他还表示这是一个 clang 错误:https://bugs.llvm.org/show_bug.cgi?id=47509

Rafael Ávila de Espíndola 将问题归结为以下代码,该代码使用 gcc 编译,但不使用 clang:

template <typename _Tp>
concept __member_begin = requires(_Tp __t) {
    {__t.begin()};
};
template <typename _Tp>
concept nothing = requires(_Tp __t) {
    {42};
};
template <typename _Tp>
requires __member_begin<_Tp> void __ranges_begin() {}
template <typename _Derived>
struct view_interface {
    void foo() requires __member_begin<_Derived> {}
    void bar() requires nothing<decltype(__ranges_begin<_Derived>())> {}
};
struct drop_view : public view_interface<drop_view> {};

clang 抱怨 (https://godbolt.org/z/4c45oKMKK):

<source>:14:42: error: no matching function for call to '__ranges_begin'
    void bar() requires nothing<decltype(__ranges_begin<_Derived>())> {}
                                         ^~~~~~~~~~~~~~~~~~~~~~~~

那么问题来了,谁是对的?这段代码是否应该编译?

还有一个更有趣的问题:我们可以用 clang 设置工作范围吗?

[temp.inst]/17:

The type-constraints and requires-clause of a template specialization or member function are not instantiated along with the specialization or function itself, even for a member function of a local class; substitution into the atomic constraints formed from them is instead performed as specified in [temp.constr.decl] and [temp.constr.atomic] when determining whether the constraints are satisfied or as specified in [temp.constr.decl] when comparing declarations.

Clang 错误。

根据 T.C 的 link 的回答,我在标准中找到了一个相关示例,clang 拒绝编译。这清楚地表明 clang 中存在错误。

[temp.constr.decl]/4:

template <class T> concept C = true;
template <class T> struct A {
  template <class U> U f(U) requires C<typename T::type>;   // #1
  template <class U> U f(U) requires C<T>;                  // #2
};

template <> template <class U>
U A<int>::f(U u) requires C<int> { return u; }              // OK, specializes #2

clang output:

<source>:3:49: error: type 'int' cannot be used prior to '::' because it has no members
  template <class U> U f(U) requires C<typename T::type>;   // #1
                                                ^

我为此创建了一个专用错误:https://bugs.llvm.org/show_bug.cgi?id=50864