On 10.07.2018 10:46, Ian Collins wrote:
> On 10/07/18 20:41, Alf P. Steinbach wrote:
> [snip]
>>
>> --------------------------------------------------------------------
>> #include <type_traits> // std::is_integral_v
>> #include <utility> // std::enable_if_t
>> using namespace std;
>>
>> template<class Number, class = enable_if_t<is_integral_v<Number>>>
>> auto mod( Number a, Number b )
>> -> Number
>> { return a%b; }
>
> Given your love of suffix return, I'm surprised you don't use C++ >= 14
> rules and simply write:
>
> template<class Number, class = enable_if_t<is_integral_v<Number>>>
> auto mod( Number a, Number b ) { return a%b; }
That would not be a suffix return (trailing return type), that would be
a deduced return type.
Which is a different beast altogether, just unfortunately reusing the
same keyword `auto`.
IMHO new keywords should have been introduced, distinguishing one syntax
from the other. E.g. it would be easy to place those keywords in
namespace `std` and allow an implementation to provide an implicit
`using namespace std::keywords;`, which one for the in-practice could
suppress via some option, an opt out scheme for legacy code.
---
Re the terminology, I'd prefer that one call a deduced return type an
/implicit return type/, because
void foo( int x ) -> decltype( log( x ) ) { return log( x ); }
clearly deduces the return type, but uses trailing return type syntax.
And also because we have the term "implicit int" from old C as
established practice for naming, well, implicit return types.
However, there is a proposal for "implicit return type" to mean
something else, <url:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0224r0.html>. I
think that's unfortunate. And I don't get why people think it would be a
good idea to add more and more exceptions to the syntax of the language.
In any event I think we can just disregard that proposal. Even if it
should get adopted into C++20, or whatever.
---
For the above code an implicit return type would not add any useful
functionality but would make the return type depend on the return
statement's expression, which some maintainer could conceivably change
to invoke a second function with implicit return type, and so on, so
that one would have to hunt all over the code base for the actual type.
It gets messy fast so I recommend to avoid implicit return types where
they don't confer any benefit other than saving some keystrokes.
An implicit return type /with both arguments templated/ could serve a
purpose for this function, as exemplified below, but that wasn't what I
was trying to exemplify earlier, and I decided to keep it simple.
-------------------------------------------------------------------------
#include <type_traits> // std::is_integral_v
#include <utility> // std::enable_if_t
using namespace std;
template< class Number_A, class Number_B
, class = enable_if_t< is_integral_v< Number_A > and is_integral_v<
Number_B > >
>
auto mod( Number_A a, Number_B b )
{ return a%b; }
#include <iostream>
int main()
{
const int a = mod( 13, 5 );
#ifdef TEST
const double b = mod( 13.0, 5.0 ); //! Won't compile.
#endif
}
-------------------------------------------------------------------------
To see what this corresponded to in C++03 it can probably be instructive
to revisit Andrei Alexandrescu's 2001 DDJ article "Generic: Min and Max
Redivivus", at <url:
http://www.drdobbs.com/generic-min-and-max-redivivus/184403774>.
Crucially, C++03 lacked `decltype`.
Cheers!,
- Alf