Using a class inside the requires-clause for the method of this class

264 Views Asked by At

Here is the simple example:

#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 } );
}

According to Godbolt this example compiles successfully on MSVC and GCC, but fails to compile on Clang. What does the standard say about such require-expressions?

Update: we might simplify the example so that there is no circularity in methods calls (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 } );
}

The compilers act the same way as for the original example.

1

There are 1 best solutions below

1
On

[temp.inst]/17 arguably supports at least the non-circularity example, at the very least if MyClass is a class template [emphasis mine]:

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.

As, for a class template, [temp.inst]/11 holds:

An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class or static data member of a templated class, or a substatement of a constexpr if statement ([stmt.if]), unless such instantiation is required.

Clang accepts both examples if MyClass is made into a class template (circularity DEMO, non-circularity DEMO).

[temp.inst]/17 could be argued to apply also for a non-template classes given its statement about local classes, as local classes are not allowed to be class templates, meaning Clang rejects-invalid at least the non-circularity example.