Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: template declaration synthax

32 views
Skip to first unread message

Paavo Helde

unread,
Jul 9, 2018, 3:06:25 PM7/9/18
to
On 9.07.2018 21:14, Soviet_Mario wrote:
> how can one declare a typename (in the template declaration) to be an
> enumvalue ?
> Or else, is it possible to passa a "typeless" (= less strict) integral
> value to a template ?
>
> I remember 15 y ago I found how to declare templates with compile time
> resolved fixed (but parametric) size arrays
>
> like in
> template <?? "int" Param> class Buffer
> {
> private:
> char [Param] zBuf;

enum A { small = 512, large = 10000 };

template <A Param> class Buffer
{
private:
char zBuf[Param];
};

int main() {
Buffer<A::large> x;

}


Alf P. Steinbach

unread,
Jul 9, 2018, 3:16:49 PM7/9/18
to
On 09.07.2018 20:22, Soviet_Mario wrote:
> Il 09/07/2018 20:14, Soviet_Mario ha scritto:
>> how can one declare a typename (in the template declaration) to be an
>> enumvalue ?
>> Or else, is it possible to passa a "typeless" (= less strict) integral
>> value to a template ?
>>
>> I remember 15 y ago I found how to declare templates with compile time
>> resolved fixed (but parametric) size arrays
>>
>> like in
>> template <?? "int" Param> class Buffer
>> {
>> private:
>> char [Param] zBuf;
>>
>> ...
>> ...
>>
>> }

For example

template< int param >
class Buffer ...


> sorry I mispressed RETURN before completing the post :\
>
> I also wanted to ask a question : whether or not (and how) in "plain"
> C++ would be possible to specify (always in a template) a typename WITH
> RESTRICTIONS (as in VStudio extension).

Check out `std::enable_if` & friends.

For example,

template< class Number, class = enable_if_t< is_integral_v<Number> >
auto mod( Number a, Number b ) -> Number { return a%b; }


> With restriction I mean, a typename parameter must be within a subset of
> types, specified in some form (ex. in brackets).

You might be able to leverage std::tuple for that.

Otherwise, it can be a good exercise to make your own type list.

[snip]


Cheers!,

- Alf

Soviet_Mario

unread,
Jul 9, 2018, 3:18:08 PM7/9/18
to
I'm going to document myself about this feature, thanks for
signalling me !

>
>
>> With restriction I mean, a typename parameter must be
>> within a subset of types, specified in some form (ex. in
>> brackets).
>
> You might be able to leverage std::tuple for that.

oh ... I used to think this feature was only supported by
BOOST (who was very complex to compile and slow). I'm very
glad that now tuple become part of standard !

>
> Otherwise, it can be a good exercise to make  your own type
> list.

No tnx, I'm just grasping trying to use more rock solid
components written by more skilled progrtammers and debugged
well. I've lost all my juvenile hubris in trying these things :)
TY

there's only one case when I try to code myself : when I
really can't understand the logic of the existing components
and doubt about using them as intended. In that case, I
prefer to suspect where errors may hide to suspecting period.

>
> [snip]
>
>
> Cheers!,
>
> - Alf


--
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)

Soviet_Mario

unread,
Jul 9, 2018, 3:18:28 PM7/9/18
to
perfect, always crystal clear :)

Soviet_Mario

unread,
Jul 9, 2018, 3:30:03 PM7/9/18
to
how can one declare a typename (in the template declaration)
to be an enumvalue ?
Or else, is it possible to passa a "typeless" (= less
strict) integral value to a template ?

I remember 15 y ago I found how to declare templates with
compile time resolved fixed (but parametric) size arrays

like in
template <?? "int" Param> class Buffer
{
private:
char [Param] zBuf;

...
...

}


the enum solution would be better for other reasons (memory
alignment, interoperability with other pieces of sw
expecting "fixed size" chunks of memory flexible but not
arbitrary)

Tnx in advance for suggestions :\

Soviet_Mario

unread,
Jul 9, 2018, 3:38:16 PM7/9/18
to
Il 09/07/2018 20:14, Soviet_Mario ha scritto:
> how can one declare a typename (in the template declaration)
> to be an enumvalue ?
> Or else, is it possible to passa a "typeless" (= less
> strict) integral value to a template ?
>
> I remember 15 y ago I found how to declare templates with
> compile time resolved fixed (but parametric) size arrays
>
> like in
> template <?? "int" Param> class Buffer
> {
> private:
> char [Param] zBuf;
>
> ...
> ...
>
> }


sorry I mispressed RETURN before completing the post :\

I also wanted to ask a question : whether or not (and how)
in "plain" C++ would be possible to specify (always in a
template) a typename WITH RESTRICTIONS (as in VStudio
extension).

With restriction I mean, a typename parameter must be within
a subset of types, specified in some form (ex. in brackets).

I'm not intersted to obtain INTERFACE filter, just to filter
types.

That is for the fact that non necessarily a template logic
is consistent with every type ! I mean, a template built fo
manage number and quantities in calculation would be
meaningless passing "std::string" as a typename parameter
(as strings can hold illegal number values).

How to restrict the space of typenames to a subset, stating
legal types ?

Re-thanks

red floyd

unread,
Jul 9, 2018, 4:24:41 PM7/9/18
to
On 7/9/2018 12:18 PM, Soviet_Mario wrote:
> Il 09/07/2018 21:06, Paavo Helde ha scritto:
>> On 9.07.2018 21:14, Soviet_Mario wrote:
>>> how can one declare a typename (in the template declaration) to be an
>>> enumvalue ?
>>> Or else, is it possible to passa a "typeless" (= less strict) integral
>>> value to a template ?
>>>
>>> I remember 15 y ago I found how to declare templates with compile time
>>> resolved fixed (but parametric) size arrays
>>>
>>> like in
>>> template <?? "int" Param> class Buffer
>>> {
>>> private:
>>> char [Param] zBuf;
>>
>> enum A { small = 512, large = 10000 };
>>
>> template <A Param> class Buffer
>> {
>> private:
>>      char zBuf[Param];
>> };
>>
>> int main() {
>>      Buffer<A::large> x;
>>
>> }
>>
>>
>
> perfect, always crystal clear :)
>
>

Paavo has given the correct answer, but you might want to declare as
follows:

#include <array>

enum A { small = 512, large = 10000 };
template <A param> class Buffer
{
private:
std:array<char, param> zBuf;
// other methods here
};

std:array has no extra overhead.


Scott Lurndal

unread,
Jul 9, 2018, 4:41:48 PM7/9/18
to
Personally, I'd rather see 'char zBuf[param];'. I see no benefit in
another layer of abstraction over a native type.

Vir Campestris

unread,
Jul 9, 2018, 4:49:30 PM7/9/18
to
On 09/07/2018 21:24, red floyd wrote:
> std:array has no extra overhead.

Maybe, but it does need a second colon

std::array

(as I'm sure you know, but the OP might not.)

Andy

Soviet_Mario

unread,
Jul 9, 2018, 7:26:55 PM7/9/18
to
I agree, in case of a STATIC array who does not offer
dynamic resizing and other extras ...

Soviet_Mario

unread,
Jul 9, 2018, 9:05:19 PM7/9/18
to
Il 09/07/2018 21:04, Alf P. Steinbach ha scritto:
sorry, I feel dumb but as the topic is not my cup of tea ...
I see 3 open angular < and two closed >.

Surely it is trivial typo, but the third > would simply be
after the consecutive closed (with a space not to be parsed
as >> op. True ?
Sorry for the futile remark, but ... well, I'm not that sure
where it should go.



>
>> With restriction I mean, a typename parameter must be
>> within a subset of types, specified in some form (ex. in
>> brackets).
>
> You might be able to leverage std::tuple for that.
>
> Otherwise, it can be a good exercise to make  your own type
> list.
>
> [snip]
>
>
> Cheers!,
>
> - Alf


red floyd

unread,
Jul 9, 2018, 9:17:29 PM7/9/18
to
Thanks. Typos happen.

Alf P. Steinbach

unread,
Jul 10, 2018, 4:41:11 AM7/10/18
to
On 10.07.2018 03:05, Soviet_Mario wrote:
> Il 09/07/2018 21:04, Alf P. Steinbach ha scritto:
>> [snip]
>> For example,
>>
>>      template< class Number, class = enable_if_t< is_integral_v<Number> >
>>      auto mod( Number a, Number b ) -> Number { return a%b; }
>>
>
> sorry, I feel dumb but as the topic is not my cup of tea ... I see 3
> open angular < and two closed >.
>
> Surely it is trivial typo, but the third > would simply be after the
> consecutive closed (with a space not to be parsed as >> op.   True ?
> Sorry for the futile remark, but ... well, I'm not that sure where it
> should go.

Yes, just place it at the end. The spaces are not really necessary in
C++11 and later.

--------------------------------------------------------------------
#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; }

#include <iostream>
int main()
{
const int a = mod( 13, 5 );
#ifdef TEST
const double b = mod( 13.0, 5.0 ); //! Won't compile.
#endif
}
--------------------------------------------------------------------


Since this code uses `is_integral_v` you need to specify C++17 or later
to compile it. Or you can rewrite as `is_integral<Number>::value`. Or,
if you want to support pre-C++17 compilers and find that too verbose,
define a `constexpr` function to get this info at compile time.


Cheers!,

- Alf

Ian Collins

unread,
Jul 10, 2018, 4:47:01 AM7/10/18
to
On 10/07/18 20:41, Alf P. Steinbach wrote:
> On 10.07.2018 03:05, Soviet_Mario wrote:
>> Il 09/07/2018 21:04, Alf P. Steinbach ha scritto:
>>> [snip]
>>> For example,
>>>
>>>      template< class Number, class = enable_if_t< is_integral_v<Number> >
>>>      auto mod( Number a, Number b ) -> Number { return a%b; }
>>>
>>
>> sorry, I feel dumb but as the topic is not my cup of tea ... I see 3
>> open angular < and two closed >.
>>
>> Surely it is trivial typo, but the third > would simply be after the
>> consecutive closed (with a space not to be parsed as >> op.   True ?
>> Sorry for the futile remark, but ... well, I'm not that sure where it
>> should go.
>
> Yes, just place it at the end. The spaces are not really necessary in
> C++11 and later.
>
> --------------------------------------------------------------------
> #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; }

--
Ian.

Alf P. Steinbach

unread,
Jul 10, 2018, 5:22:39 AM7/10/18
to
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

Soviet_Mario

unread,
Jul 10, 2018, 5:35:05 AM7/10/18
to
Il 10/07/2018 10:41, Alf P. Steinbach ha scritto:
> On 10.07.2018 03:05, Soviet_Mario wrote:
>> Il 09/07/2018 21:04, Alf P. Steinbach ha scritto:
>>> [snip]
>>> For example,
>>>
>>>      template< class Number, class = enable_if_t<
>>> is_integral_v<Number> >
>>>      auto mod( Number a, Number b ) -> Number { return
>>> a%b; }
>>>
>>
>> sorry, I feel dumb but as the topic is not my cup of tea
>> ... I see 3 open angular < and two closed >.
>>
>> Surely it is trivial typo, but the third > would simply be
>> after the consecutive closed (with a space not to be
>> parsed as >> op.   True ?
>> Sorry for the futile remark, but ... well, I'm not that
>> sure where it should go.
>
> Yes, just place it at the end. The spaces are not really
> necessary in C++11 and later.
>
> --------------------------------------------------------------------
>
> #include <type_traits>      // std::is_integral_v

mmm, I searched textually, but THERE I only find is_integral
without the _v suffix ... strange, but in my header there
is no mention to your macro.
Which differences would be supposed to have the two versions ?

> #include <utility>          // std::enable_if_t

this one I didn't include ... I'll proceed (strangely the
synthax colorizing just worked on this construct)

> using namespace std;
>
>  template<class Number, class =
> enable_if_t<is_integral_v<Number>>>
>  auto mod( Number a, Number b )
>     -> Number
> { 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
> }
> --------------------------------------------------------------------
>
>
>
> Since this code uses `is_integral_v` you need to specify
> C++17 or later to compile it. Or you can rewrite as
> `is_integral<Number>::value`.

yes I see this one in my header

> Or, if you want to support
> pre-C++17 compilers and find that too verbose, define a
> `constexpr` function to get this info at compile time.

I use QT Creator ... and I must admit I did not configure
almost anything, he uses the compiler installed by default
on the system :(

>
>
> Cheers!,

TY for precious help

Alf P. Steinbach

unread,
Jul 10, 2018, 6:31:08 AM7/10/18
to
On 10.07.2018 11:34, Soviet_Mario wrote:
> Il 10/07/2018 10:41, Alf P. Steinbach ha scritto:
>> [snip]
>> --------------------------------------------------------------------
>> #include <type_traits>      // std::is_integral_v
>
> mmm, I searched textually, but THERE I only find is_integral  without
> the _v suffix ... strange, but in my header there is no mention to your
> macro.

It's not a macro, it's a C++17 template variable, defined by the
standard library like

template< class Type >
constexpr bool is_integral_v = is_integral<Type>::value;

This language feature was introduced in C++17, so you can't do exactly
the same when compiling as C++14 or C++11.

But you can define a C++11 `constexpr` function, to reduce the verbosity
in the calling code:

template< class Type >
constexpr auto is_integral_()
-> bool
{ return std::is_integral<Type>::value; }

... and use it like `is_integral<My_type>()`.


> Which differences would be supposed to have the two versions ?

For `is_integral_v` C++17 or higher must be specified.

Also, one must use a compiler version that supports this stuff. E.g. as
I recall g++ had some quite baffling omissions in earlier versions.


>> #include <utility>          // std::enable_if_t
>
> this one I didn't include ... I'll proceed (strangely the synthax
> colorizing just worked on this construct)

In C++, as opposed to C, a standard library header is unfortunately
permitted to include any other standard library header, at the whim of
the implementation.

That means that even though omitting that `#include` works with a
particular compiler, it may not necessarily work with some other compiler.

I don't know any way to test conclusively that one has included all
headers necessary for portable code. :( Apparently one must just compile
with at least two different popular compilers and trust that that covers
enough variation to make the code reasonably portable. Other clc++
denizens may however know of tools and techniques for this that I'm
unaware of; it's a big-ish tools universe...


>> using namespace std;
>>
>>   template<class Number, class = enable_if_t<is_integral_v<Number>>>
>>   auto mod( Number a, Number b )
>>      -> Number
>> { 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
>> }
>> --------------------------------------------------------------------
>>
>>
>> Since this code uses `is_integral_v` you need to specify C++17 or
>> later to compile it. Or you can rewrite as `is_integral<Number>::value`.
>
> yes I see this one in my header
>
>> Or, if you want to support pre-C++17 compilers and find that too
>> verbose, define a `constexpr` function to get this info at compile time.
>
> I use QT Creator ... and I must admit I did not configure almost
> anything, he uses the compiler installed by default on the system :(

One day I really must try out QT Creator. After all it's Norwegian. But
I shied away from Qt many years ago when the installation dialog showed
clear signs of *nix origins by failing to handle the backspace key for
editing and possibly (I'm not sure now, but it's common for that kind of
software origins) insisting on paths with no spaces, or else suffer.

Cheers!,

- Alf

Jorgen Grahn

unread,
Aug 1, 2018, 3:16:43 PM8/1/18
to
On Mon, 2018-07-09, Scott Lurndal wrote:
> red floyd <dont....@its.invalid> writes:
>>On 7/9/2018 12:18 PM, Soviet_Mario wrote:
>>> Il 09/07/2018 21:06, Paavo Helde ha scritto:
>>>> On 9.07.2018 21:14, Soviet_Mario wrote:
>>>>> how can one declare a typename (in the template declaration) to be an
>>>>> enumvalue ?
>>>>> Or else, is it possible to passa a "typeless" (= less strict) integral
>>>>> value to a template ?
>>>>>
>>>>> I remember 15 y ago I found how to declare templates with compile time
>>>>> resolved fixed (but parametric) size arrays

...

>>Paavo has given the correct answer, but you might want to declare as
>>follows:
>>
>>#include <array>
>>
>>enum A { small = 512, large = 10000 };
>>template <A param> class Buffer
>>{
>>private:
>> std:array<char, param> zBuf;
>>// other methods here
>>};
>>
>>std:array has no extra overhead.

> Personally, I'd rather see 'char zBuf[param];'. I see no benefit in
> another layer of abstraction over a native type.

It's perhaps the most error-prone native types, and std::array
addresses some of that -- it's not a useless layer.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
0 new messages