Date: Thu, 31 Oct 2019 22:17:35 +0300
On 2019-10-31 20:54, Andrey Semashev wrote:
> On 2019-10-31 15:15, Dmitry wrote:
>>
>> Decomposing the type to know the template parameters is not the
>> same as
>> making these parameters part of the class' public interface.
>>
>>
>> Right, not exactly the same.
>>
>> There are
>> cases when template parameters are used for auxiliary purposes, e.g.
>> for
>> SFINAE or tagging and specialization. These parameters should not be
>> exposed.
>>
>> It looks like this statement is the most important thing. And I am
>> struggling to understand why it is so. Can you please elaborate on
>> this more? Why do you think it is a bad idea? (I hope you read my
>> proposal and know that if there is already a user-defined type with
>> the same name, they won't be declared).
>
> I did not read the paper, but name clashes is not my main point above.
> Currently, template parameter names are not part of the class interface.
> Even some trailing template parameters themselves may not be intended
> for public use, although careful programmers would hide those with
> template aliases or inheritance.
>
> template< typename T, bool F = is_empty_v<T> && !is_final_v<T> >
> struct is_ebo_viable_impl : false_type {};
>
> template< typename T >
> struct is_ebo_viable_impl< T, true > : true_type {};
>
> template< typename T >
> using is_ebo_viable = is_ebo_viable_impl< T >;
>
> In this example, neither T nor F names are the public interface of
> is_ebo_viable or is_ebo_viable_impl. The F parameter itself is not even
> intended to be used by users, it is an implementation detail. If those
> names became visible to users, that would mean they are now part of the
> class interface, which is not the intention. Worse, there would be no
> way to hide F, which is_ebo_viable attempts to achieve.
>
> Adding unintended members to types can have practical consequences. For
> example, various type inspection techniques can be broken.
>
> template< typename type >
> struct foo {};
>
> template< typename T >
> struct has_type
> {
> static constexpr value = ...; // true if T::type is a type
> };
>
> has_type<foo>::value is false now, but with the implicit template
> parameter names propagation it would become true.
>
>
> Speaking of name clashes, I think it should be a hard error if a
> template parameter name clashes a member name, when parameter name
> propagation is requested.
>
> template< public typename T >
> struct foo
> {
> typedef int T; // error: member type T already defined
> // by the template parameter
> };
>
> This will avoid the ambiguity as to what T actually is for the less
> experienced developers.
For completeness, requesting name propagation for an unnamed template
parameter should also be a hard error.
> On 2019-10-31 15:15, Dmitry wrote:
>>
>> Decomposing the type to know the template parameters is not the
>> same as
>> making these parameters part of the class' public interface.
>>
>>
>> Right, not exactly the same.
>>
>> There are
>> cases when template parameters are used for auxiliary purposes, e.g.
>> for
>> SFINAE or tagging and specialization. These parameters should not be
>> exposed.
>>
>> It looks like this statement is the most important thing. And I am
>> struggling to understand why it is so. Can you please elaborate on
>> this more? Why do you think it is a bad idea? (I hope you read my
>> proposal and know that if there is already a user-defined type with
>> the same name, they won't be declared).
>
> I did not read the paper, but name clashes is not my main point above.
> Currently, template parameter names are not part of the class interface.
> Even some trailing template parameters themselves may not be intended
> for public use, although careful programmers would hide those with
> template aliases or inheritance.
>
> template< typename T, bool F = is_empty_v<T> && !is_final_v<T> >
> struct is_ebo_viable_impl : false_type {};
>
> template< typename T >
> struct is_ebo_viable_impl< T, true > : true_type {};
>
> template< typename T >
> using is_ebo_viable = is_ebo_viable_impl< T >;
>
> In this example, neither T nor F names are the public interface of
> is_ebo_viable or is_ebo_viable_impl. The F parameter itself is not even
> intended to be used by users, it is an implementation detail. If those
> names became visible to users, that would mean they are now part of the
> class interface, which is not the intention. Worse, there would be no
> way to hide F, which is_ebo_viable attempts to achieve.
>
> Adding unintended members to types can have practical consequences. For
> example, various type inspection techniques can be broken.
>
> template< typename type >
> struct foo {};
>
> template< typename T >
> struct has_type
> {
> static constexpr value = ...; // true if T::type is a type
> };
>
> has_type<foo>::value is false now, but with the implicit template
> parameter names propagation it would become true.
>
>
> Speaking of name clashes, I think it should be a hard error if a
> template parameter name clashes a member name, when parameter name
> propagation is requested.
>
> template< public typename T >
> struct foo
> {
> typedef int T; // error: member type T already defined
> // by the template parameter
> };
>
> This will avoid the ambiguity as to what T actually is for the less
> experienced developers.
For completeness, requesting name propagation for an unnamed template
parameter should also be a hard error.
Received on 2019-10-31 14:19:57