在此类的方法的 require 子句中使用类

And*_*rew 11 c++ language-lawyer compiler-specific c++-concepts c++20

这是一个简单的例子:

#include <type_traits>
#include <ranges>
#include <vector>

struct MyClass
{
    void f( int ) {}
    void f( char ) {}

    template <std::ranges::input_range Rng>
        requires requires ( MyClass cls, const std::ranges::range_value_t<Rng>& val )
        {
            { cls.f( val ) };
        }
    void f( Rng&& rng ) {}
};

int main()
{
    MyClass cls;
    cls.f( 10 );
    cls.f( 'a' );
    cls.f( std::vector<int>{ 10, 15 } );
}
Run Code Online (Sandbox Code Playgroud)

根据Godbolt 的说法,这个示例在 MSVC 和 GCC 上编译成功,但在 Clang 上编译失败。标准对此类要求表达式有何规定?

更新:我们可以简化示例,以便方法调用中不存在循环(Godbolt):

#include <type_traits>
#include <ranges>
#include <vector>

struct MyClass
{
    void g( int ) {}
    void g( char ) {}

    template <std::ranges::input_range Rng>
        requires requires ( MyClass cls, const std::ranges::range_value_t<Rng>& val )
        {
            { cls.g( val ) };
        }
    void f( Rng&& rng ) {}
};

int main()
{
    MyClass cls;
    cls.g( 10 );
    cls.g( 'a' );
    cls.f( std::vector<int>{ 10, 15 } );
}
Run Code Online (Sandbox Code Playgroud)

编译器的行为方式与原始示例相同。

dfr*_*fri 2

[temp.inst]/17可以说至少支持非循环示例,至少 ifMyClass是一个类模板 [强调我的]:

模板特化或成员函数的类型约束需求子句不会与特化或函数本身一起实例化,即使对于局部类的成员函数也是如此;当确定约束是否满足时,替换为由它们形成的原子约束,而是按照 [temp.constr.decl] 和 [temp.constr.atomic] 中的指定执行,或者在比较声明时按照 [temp.constr.decl] 中的指定执行。

对于类模板,[temp.inst]/11成立:

实现不得隐式实例化函数模板、变量模板、成员模板、非虚成员函数、模板类的成员类或静态数据成员,或者 constexpr if 语句的子语句 ([stmt.if ]),除非需要这样的实例化。

MyClass如果 Clang被制作成类模板(circularity DEMOnon-circularity DEMO ) ,则接受这两个示例。

[temp.inst]/17 可能会被认为也适用于非模板类,因为它关于本地类的声明,因为本地类不允许成为类模板,这意味着 Clang 至少拒绝无效的非循环示例。