C++ Logo


Advanced search

Re: [std-proposals] Explicit keyword for template parameters

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Sat, 30 Apr 2022 09:56:55 -0400
On Sat, Apr 30, 2022 at 6:04 AM Frederick Virchanza Gotham via
Std-Proposals <std-proposals_at_[hidden]> wrote:
> On Saturday, April 30, 2022, Jens Maurer <Jens.Maurer_at_[hidden]> wrote:
>> If you want to disable template argument deduction for a function parameter,
>> just do it (see [meta.trans.other]):
>> template<class T>
>> /* whatever */ Add_Or_Max(std::type_identity_t<T> const a, std::type_identity_t<T> const b);
>> Since T only appears in non-deduced contexts, a user needs to specify
>> it explicitly in the template-argument-list of the function call.
> Nobody wants to open up a colleague's SVN commit and scroll down through code that looks like that. It isn't streamlined to read, especially when you're thinking about 2 or 3 things at once, and then you have to think "oh I know that trick there with type_identity_t". The following is much more minimalist and easy to understand at a glance:
> template<explicit class T>
> T Add_Or_Max(T a, T b);
> We designers of computer programming languages (or we hobbyists with an interest in designing computer programming languages), must empower the programmer to write minimal clean code to get the job done well -- such as when 'virtual' methods were invented so that we could have abstract base classes.

Here's the thing. You are not talking about a feature that will
empower programmers with new capabilities. You're talking about a
feature which will empower the compiler to *stop programmers* from
using certain language features in specific situations. The only
purpose of your feature is to make certain currently legal code
illegal via an opt-in mechanism.

That is, it doesn't help a programmer solve a programming problem; it
helps a programmer prevent other programmers from doing something that
they consider to be dubious in a particular scenario. It's not like
`virtual`; it's like `override`: a thing that forces you to be more
clear about what you're doing.

And don't misunderstand me; tools like that are important. But you
can't really compare it to a feature that empowers programmers to more
effectively solve programming problems.

However, the thing is, while you might personally use this tool
throughout your application, I suspect that not a lot of people would
do so. So, while it is a viable thing, is it really important enough
to warrant a language change?

If `std::type_identity_t<T>` is too unsightly for your needs, you
could easily make an equivalent that's shorter and more clear:

template<typename T>
using explicit_t = std::type_identity_t<T>;

template<class T>
T Add_Or_Max(explicit_t<T> a, explicit_t<T> b);

Yes, it's still on the function's parameters and not the template's
parameters. But `std::type_identity_t` was added specifically to
prevent template argument deduction (see P0887).

My overall points are:

1. This is a pretty niche issue. That is, while you might use it very
frequently, most programmers only need it situationally.

2. It's an issue that you can already solve, if a bit inelegantly.
It's hardly as involved as manually implementing vtables.

It should also be noted that `type_identity_t` is *better* than your
suggestion in one way. Because it's a part of a function's parameters,
it works on non-template constructors of a *class template*. That is,
you can use it to conditionally shut off CTAD for particular

Your method of putting `explicit` on a template parameter would force
*all* constructors that use that template parameter to be non-deduced.
What you usually want is to make a particular constructor's use of
that parameter to be non-deduced. `type_identity_t` does that.

> I know that we can use 'type_identity_t' here but it's clunky syntax which interrupts the reader's train of thought. Also it involves including a standard header file <type_traits> simply just to declare a function.

That last part can be avoided by just rolling your own.
`std::type_identity_t` is 5 lines of code:

template<typename T>
struct explicit_type { using type = T; };

template<typename T>
explicit_t = explicit_type<T>::type;

Received on 2022-04-30 13:57:45