cplusplus / CWG

Core Working Group
24 stars 7 forks source link

[over.over] Is CWG2369 supposed to change the order of subsitution or elimination #611

Open ranaanoop opened 3 weeks ago

ranaanoop commented 3 weeks ago

Full name of submitter: Anoop Rana

Reference (section label): [over.over]

Link to reflector thread (if any): https://stackoverflow.com/questions/79016821/static-assertion-fires-from-return-type-when-leading-constraint-is-not-satisfied

Issue description:

Consider the following example for which we observe implementation divergence.

template<typename T>
constexpr int assert() {
    static_assert(sizeof(T) == 1);
    return 1;
}

template<auto I>
using Int = int;

template<typename T> requires (sizeof(T) == 1)
constexpr auto foo(T) -> Int<assert<T>()> {
    return 1;
}

template<typename T> requires (sizeof(T) > 1)
constexpr auto foo(T a) -> Int<1> {
    return 2;
}

static_assert(foo(2) == 2);

[over.over#5] seems/intented to make this well-formed but as pointed out in the thread, [over.over#3] seems to make this ill-formed.

Suggested resolution:

Clarify the order.

frederick-vs-ja commented 3 weeks ago

IIRC among these 3 major compilers, only GCC has implemented CWG2369. So I think it's too early to talk about implementation divergence at this moment.

keinflue commented 3 weeks ago

sizeof(int) == 1 is possible.

Ignoring that, why should [over.over]/5 be relevant? Template argument deduction fails for the first foo template, so it doesn't produce any specialization that would be added to the candidate set per [over.over]/3. Further removal of candidates later on doesn't matter.

And CWG 2369 specifies that assert<int> is not instantiated in the process of template argument deduction for the failing foo overload.

Also, more importantly, [over.over] doesn't apply to the call foo(2). It is about overload resolution when addresses of overload sets are taken.

Instead the candidate set is formed according to [over.match.funcs.general] and [over.match.call].