cplusplus / CWG

Core Working Group
23 stars 7 forks source link

CWG2847 [temp.expl.spec] Constrained class scope explicit specializations of function templates #482

Open sdkrystian opened 6 months ago

sdkrystian commented 6 months ago

Full name of submitter Krystian Stasiowski

Reference (section label): [temp.expl.spec]

Link to reflector thread (if any):

Issue description:

(Note: I originally submitted this by email in November, but I'm not sure if email submissions are accepted anymore)

The resolution of CWG 727 made function template explicit specialization declarations at class scope well formed. Unlike explicit specializations of class/variable templates, such declarations can be constrained with a trailing requires-clause. Given that an explicit specialization is required to satisfy the associated constraints of its primary template, it is not clear whether the trailing requires-clause should be equivalent to that of primary template, or if it should be permitted at all.

There is significant implementation variance for the following:

template<typename T>
concept C = sizeof(T) > sizeof(char);
template<typename T>
concept D =  sizeof(T) > sizeof(int) ;

template<typename T>
struct A 
{
    template<typename U>
    constexpr int f(U) requires C<U> { return 0; }

    template<>
    constexpr int f(int) requires D<T> { return 1; }
};

static_assert(A<int>().f(0) == 0);

GCC does not permit class scope function template explicit specializations, clang rejects them if a trailing requires-clause is present, and EDG accepts the trailing requires-clause but ignores the constraint, causing the static_assert to fail.

Suggested resolution:

Add a new paragraph after [temp.expl.spec] p18: An explicit specialization shall not have a trailing requires-clause ([dcl.decl.general]) unless it declares a function template.

[Example:
    template<typename T>
    concept C = sizeof(T) <= sizeof(int);

    template<typename T>
    struct A {
        template<typename U>
        void f(U) requires C<U>;

        template<>
        void f(char); // OK

        template<>
        void f(short) requires true; // error: trailing requires-clause not permitted
    };

    template<>
    template<typename U>
    void A<int>::f(U) requires C<U>; // OK, explicit specialization of a member function template of a class template is a template
-- end example]
jensmaurer commented 5 months ago

CWG2847