C++ Logo

std-proposals

Advanced search

Re: Explicit alias template specialization

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Fri, 19 Nov 2021 18:28:22 +0100
pt., 19 lis 2021 o 17:56 Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]> napisał(a):
>
> On Fri, Nov 19, 2021 at 11:36 AM Marcin Jaczewski via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>
>> pt., 19 lis 2021 o 17:28 Matheus Izvekov via Std-Proposals <std-proposals_at_[hidden]> napisał(a):
>> >
>> > On Fri, Nov 19, 2021 at 5:13 PM Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden]> wrote:
>> > > Yes, they are.
>> > > Dependent member types are (always?) non-transparent "firewalls" against deduction, but aliases are never(!) firewalls.
>> >
>> > If type aliases could be specialized as he proposed, then type aliases
>> > specializations with dependent template arguments would indeed become
>> > `firewalls` in all cases except that they could be matched one to the
>> > other (as in the example from my previous message `alias<T>` would
>> > match to `alias<int>` giving `T = int`).
>> >
>> > In the same way, it's possible to extend TAD such that dependent
>> > member types could be matched.
>> > So for example:
>> > `P = typename T::foo` and `A = X:: foo` -> `T = X`
>> > `P = typename foo<T>::bar` and `A = foo<int>::bar` -> `T = int`
>>
>> You can't go back from `bar` to `foo<T>` as `foo<T>::bar` is turing
>> complete, you would need to check every possible `T` to find a one
>> matching `bar`.
>> Simple example:
>> `P = typename T::foo` and `A = int` how to find `T` then?
>
>
> To be fair, I assume that Matheus is talking only about the "true names" of the types — like, the ones that contribute to mangling. (Do we have a standardese term for "true names"? I've never been aware of one.)
>
> So in that hypothetical (and definitely-never-gonna-happen) world where we could deep-pattern-match into true names:
>
> template<class T> struct AA { struct Nested {}; };
> template<> struct AA<double> { using Nested = AA<char>::Nested; };
> template<> struct AA<float> { using Nested = float; };
>
> template<class T> void a(AA<T>::Nested);
> void a1() { a(AA<int>::Nested()); } // deduces T=int because the "true name" of the argument type is AA<int>::Nested
> void a2() { a(AA<double>::Nested()); } // deduces T=char (not double!) because the "true name" of the argument type is AA<char>::Nested
> void a3() { a(AA<float>::Nested()); } // deduction fails because the "true name" of the argument type is float
>

Ok, if we restrict only to "true names" (mangling?) then it will work,
but how exactly will this be done?

```
template<class T> struct AA { using Nested = int; };
//or
template<class T> struct AA { /* noting */ };
//or
template<class T> struct AA; //nowhere defined
```

This will still work for `AA<T>::Nested`? You show that it can work in
specific cases
but probably it will have too many corner cases to be easily used in
generic code.

Another question is what will be difference between "fail to match"
and "do not match"?
Currently we have "firewall" that cause simply skip this argument,
but if we try to match it will fail or be silently ignored?
Depending on definition it could cause breaking change in some specific cases.



> And then we'd have:
>
> template<class T> void nonportable(std::vector<T>::iterator);
> void call_nonportable() { std::vector<int> v; nonportable(v.begin()); } // deduction fails today;
> // in the hypothetical world, deduction probably fails, but it depends on your vendor's implementation details
>
> If std::vector<int>::iterator is a typedef for __wrap_iter<int*>, then deduction would still fail; if it's a class type with no intervening aliases at all, then deduction would succeed.
>
> –Arthur

Received on 2021-11-19 11:28:36