On Fri, Jan 15, 2021 at 10:54 AM Yves Bailly via Std-Proposals <email@example.com> wrote:
First, the "stronger type alias":
using U = new T;
As you've realized (good!), the problems are going to be with T's existing customization points:
- std::swap(u, u)
using Name = new std::string;
void Store(std::string the_name); // (1)
void Store(Name the_name); // (2)
/* error */ Store("Your name here"); // ambiguous, ill-formed
FWIW, this is mildly surprising; this would be a place where `std::is_base_of_v<T, U>` and yet the signature `void(U)` is not considered more-specialized-than `void(T)`.
In fact it's precisely the point and goal of this proposal: to avoid potential surprises.
As there's an implicit conversion from char const* to std::string and to Name (this one "inherited" from std::string), then as a mere code reader I'm not sure which one Store() would be called here. As a mere code writer I may have an idea which may well be wrong. So here the suggestion is to declare the line ill-formed as ambiguous, because we have here a kind of "two-levels" implicit conversion, which is getting difficult to track.
Therefore the writer would have to make the intent explicit. After all it's the goal of strong typing: make things explicit. It seems to me it's also a general trend in C++ last years.
From what I can see, a well-known (to the "initiated") situation like this:
void foo(bool b);
void foo(std::string s);
foo("bar"); // which one is called?
...is really confusing for many developers, even experieced ones. Most developers are "just" language users, not language lawyers :-)
But I think this is just an indication that your intuition about std::is_base_of is wrong. Types with no inheritance relationships (no base classes) definitely should not claim to have is_base_of relationships.
I see the point here (I think). So indeed std::is_base_of_v<T,U> should be false. Probably std::underlying_type<> is enough to be able to query the relationship between T and U.
/* ok */ using Names_Income = std::unordered_map<Name, double>;
// std::hash<std::string> used because of
// implicit cast from Name to std::string
If there's an implicit conversion from Name to std::string, then why did you say
s = name;
I don't think I said that, on the contrary... or did I miss something?
Or are you refering to the second form called "strict type alias"?
Nice page I saw but forgot about :-)
Let me try to answer your questions, giving an answer for both suggested cases ("new T" and "explicit T"):
A: yes / yes
B: yes / no
C: yes / no
D: yes / no
E: yes / no
F: yes / yes
G: yes / yes
H: yes / no
I: yes / no