Topic: Non-type template parameter
Author: Andy Glew <glew@cs.wisc.edu>
Date: 1999/10/22 Raw View
> Pointers can be template arguments. You can't use a string literal
> because template arguments must have external linkage, but that's easily
> fixed with one more line of code.
Thanks! I had missed this!
> Well, you can do that if you don't mind being limited to integral
> values, by simply casting the integer template argument to the floating
> point type inside the template.
I do this. I even have a scaled integer - e.g.
init<double,314156,100000> pi;
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/15 Raw View
On 15 Oct 99 04:21:52 GMT, Ross Smith <ross.s@ihug.co.nz> wrote:
>Andy Glew wrote:
>> struct point {
>> init<float,-999.9999> x;
>> init<float,-86776.9879978> y;
>> };
>Well, you can do that if you don't mind being limited to integral
>values, by simply casting the integer template argument to the floating
>point type inside the template.
I think it would be nice if a type that is comprised of only integral
types is itself an integral type.
Example 1:
class Int { private: int d_data; public: ... };
Example 2:
class Silly { private: int d_data1; char d_data2; public: ... };
We could then use these more complex integral types as non-type
template arguments, or we could define them in the class (using the
common sense definition of 'define').
Consider your example:
> template <typename Channel, unsigned Unit> class Colour {
What happens if we need more descriptive parameters, like
template <typename Channel, unsigned Unit, int depth> class Colour {
But if we could define a struct Unit as
struct Unit { unsigned value; int depth; };
then we could just say
template <typename Channel, Unit unit> class Colour {
The improved notation would make our code easier to read and easier to
maintain.
--
--------------
siemel b naran
--------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/10/15 Raw View
Andy Glew <glew@cs.wisc.edu> writes:
>> > BTW, what is the reason that we can't have double as a template
>> > parameter?
>>
>> Because equality comparison of double values is inherently tricky. You
>> probably don't want your compiler instantiating two different templates,
>> one for 1.9999999999..., and a different one for 2.00000... .
>> Also, just by their very nature, doubles are a discrete approximation to
>> something that is conceptually continuous. You generally want to cope
>> with continuous variables continuously. Templates allow different but
>> related code to be defined for a large but discrete set of different
>> cases.
>You know, at first this sounded like a good argument. However,
Consider also
foo<0.1/0.01>
foo<10.0>
foo<10000000000000000000000000000000000000010.0 -
10000000000000000000000000000000000000000.0>
Mathematically, the three expressions have the same value. On
typical processors, the first two might have the value, but it
is unlikly that FP formats have enough precision to evaluate the
third as 10.0. You could have one, two, or three different
types, depending on the host and target systems.
>(1) Textual equality could be used to determine template equivalence
>where a floating point template parameter is specified.
>I.e.
> template<float f > class fc;
> fc<1.0> a;
> fc<1.00> b; // not type equivalent to a
That sounds like a really bad idea. In particular:
const double X = 1.0;
fc<X> x;
fc<1.0> y; // x and y are different types ???
If you want textual comparison, use strings.
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/10/15 Raw View
jpotter@falcon.lhup.edu (John Potter) writes:
>On 14 Oct 99 08:04:43 GMT, Hyman Rosen <hymie@prolifics.com> wrote:
>: sbnaran@uiuc.edu (Siemel B. Naran) writes:
>: > >Because he would otherwise have to define them separately?
>: > It is possible to define a static const int inside the class
>: > definition. Like this
>: > template <int lhs, int rhs>
>: > struct max { static const int result=lhs<rhs?rhs:lhs; };
>:
>: It is still necessary to define 'result' separtately. See 9.4.2/4.
>Yesterday, I agreed with this, but I'm not so sure today. That
>section says it must be defined if it is _used_ in the program. In
>an article in clc++m, Steve Clamage said that it must be defined if
>its address is taken.
I shouldn't have put it that way. Exactly what "used" means in
this case is not defined by the standard. Certainly, if you take
its address, the static object is used.
A Defect Report has been filed on this topic. The recommended
handling is to consider appearing in an integral constant expression
as not "using" the object. If that recommendation is accepted, and
you used only the value in integral constant expressions, you
would not have to provide a definition of the static member variable.
I suspect that current compilers typically behave that way.
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/10/15 Raw View
Andy Glew <glew@cs.wisc.edu> writes:
> However, it is a bit of a pity. Here's, perhaps, a more useful example:
> I have a template class init<T,init_value> that, you guessed it,
> allows an initial value to be specified in the declaration.
If the number of different initial values is limited,
you can use references to globals to accomplish what
you're trying to do -
template <class T, const T &value>
class init
{
T v;
init(const init &);
public:
init() : v(value) { }
template <class U> init &operator=(const U &o) { v = o; return *this; }
template <class U> operator U() { return v; }
};
extern const float garbage = -997.3477;
init<float,garbage> f;
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/10/14 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
| On 14 Oct 99 08:04:43 GMT, Hyman Rosen <hymie@prolifics.com> wrote:
| >sbnaran@uiuc.edu (Siemel B. Naran) writes:
|
| >> It is possible to define a static const int inside the class
| >> definition. Like this
| >
| >It is still necessary to define 'result' separtately. See 9.4.2/4.
|
| Yes, the standard says that if the static const variable does not have
| a definition outside the class, then the program is undefined. However,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The Standard is very very clear on this matter: a static data member
*definition* can appear only _ouside_ a class definition. No matter
how you spell its declaration inside the class, it is still a
*declaration*, not a definition.
| a reasonable compiler will not require the definition outside the
| class if there is a definition inside the class.
In what a C++ implementation which wouldn't allow you to use an object
without a definition should not be "reasonable"?
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Andy Glew <glew@cs.wisc.edu>
Date: 1999/10/15 Raw View
> > BTW, what is the reason that we can't have double as a template
> > parameter?
>
> template <double D> class Foobar { /*...*/ };
> typedef Foobar<1.00000000001> Foo;
> typedef Foobar<1.00000000002> Bar;
>
> Disallowing FP template arguments is just a special case of the general
> principle adopted by the C and C++ committees (largely, I gather, in
> response to the cross compilation problem) that the compiler must not be
> required to do FP arithmetic at compile time.
I'll accept this argument.
However, it is a bit of a pity. Here's, perhaps, a more useful example:
I have a template class init<T,init_value> that, you guessed it,
allows an initial value to be specified in the declaration.
I find it especially useful inside structures
struct point {
init<float,0> x;
init<float,0> y;
};
Although ) is my most common initial value, occasionally I like
using garbage values
struct point {
init<float,-999.9999> x;
init<float,-86776.9879978> y;
};
to increase the chance of catching an error. Of course, I also
have float_init_nan, double_init_nan for IEEE systems.
ASIDE: I find that specifying the initial value at member definition
greatly reduces the number of errors I get, like - I have 4 constructors,
and I remember to add a new member to all but one.
---
While we're at it, may I say that I can also imagine uses for string literals
as template parameters - e.g. specifying print_names.
print_name<int,"Branch Misprediction Count"> bmpc;
Actually, I would probably most like string template parameters so that
I can specify printf format strings to be used in printing, e.g. a value to cout.
However, I don't think that the standards committee would approve of that.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Andy Glew <glew@cs.wisc.edu>
Date: 1999/10/15 Raw View
> > BTW, what is the reason that we can't have double as a template
> > parameter?
>
> Because equality comparison of double values is inherently tricky. You
> probably don't want your compiler instantiating two different templates,
> one for 1.9999999999..., and a different one for 2.00000... .
> Also, just by their very nature, doubles are a discrete approximation to
> something that is conceptually continuous. You generally want to cope
> with continuous variables continuously. Templates allow different but
> related code to be defined for a large but discrete set of different
> cases.
You know, at first this sounded like a good argument. However,
(1) Textual equality could be used to determine template equivalence
where a floating point template parameter is specified.
I.e.
template<float f > class fc;
fc<1.0> a;
fc<1.00> b; // not type equivalent to a
fc<1.000000000000000000000000000000000000000000> c; // not equivalent to a or b
fc<1.000000000000000000000000000000000000000001> d; // not equivalent to a, b, or c
fc<1.00> f; // equivalent to a;
Dibb's on what to do if you support compile time FP arithmetic.
You could continue to support textual equivalence:
fc<4.0/4> g; // not equivalent to a
(2) Your comment about continuous ranges suggests that range predicates
would be the right way to do FP templates:
template<float f WHERE f < 0> class negative;
template<float f WHERE f > 0> class positive;
That's too far out for C/C++, but it's a worthy thought:
after all, some of us believe that template matching should be done
by predicates
template< class T WHERE EXISTS T::foo(void) > bar;
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/10/15 Raw View
On 14 Oct 99 08:04:43 GMT, Hyman Rosen <hymie@prolifics.com> wrote:
: sbnaran@uiuc.edu (Siemel B. Naran) writes:
: > >Because he would otherwise have to define them separately?
: > It is possible to define a static const int inside the class
: > definition. Like this
: > template <int lhs, int rhs>
: > struct max { static const int result=lhs<rhs?rhs:lhs; };
:
: It is still necessary to define 'result' separtately. See 9.4.2/4.
Yesterday, I agreed with this, but I'm not so sure today. That
section says it must be defined if it is _used_ in the program. In
an article in clc++m, Steve Clamage said that it must be defined if
its address is taken. Does that mean that using the value of
'result' is not using 'result' and it need not be defined? Is
binding it to a const& using it?
On the practical side, making that template available should include
the assumption that someone will take the address of result and it
should be defined somewhere.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ross Smith <ross.s@ihug.co.nz>
Date: 1999/10/15 Raw View
Andy Glew wrote:
>
> I have a template class init<T,init_value> that, you guessed it,
> allows an initial value to be specified in the declaration.
>
> I find it especially useful inside structures
>
> struct point {
> init<float,0> x;
> init<float,0> y;
> };
>
> Although ) is my most common initial value, occasionally I like
> using garbage values
>
> struct point {
> init<float,-999.9999> x;
> init<float,-86776.9879978> y;
> };
>
> to increase the chance of catching an error. Of course, I also
> have float_init_nan, double_init_nan for IEEE systems.
Well, you can do that if you don't mind being limited to integral
values, by simply casting the integer template argument to the floating
point type inside the template.
My graphics library has a Colour template that looks something like
this:
template <typename Channel, unsigned Unit> class Colour {
// Channel = type used for the RGB channels
// Unit = saturation value of a channel
public:
Colour(Channel r, Channel g, Channel b):
red(r), green(g), blue(b) {}
static Colour black() { return Colour(0, 0, 0); }
static Colour white() { return Colour(Unit, Unit, Unit); }
// ...
private:
Channel red;
Channel green;
Channel blue;
};
// Commonly used instantiations
typedef Colour<unsigned char, 255> Colour24bit;
typedef Colour<float, 1> FloatColour;
> While we're at it, may I say that I can also imagine uses for string literals
> as template parameters - e.g. specifying print_names.
>
> print_name<int,"Branch Misprediction Count"> bmpc;
>
> Actually, I would probably most like string template parameters so that
> I can specify printf format strings to be used in printing, e.g. a value to cout.
> However, I don't think that the standards committee would approve of that.
Pointers can be template arguments. You can't use a string literal
because template arguments must have external linkage, but that's easily
fixed with one more line of code. This example comes directly from the
Standard (14.3.2):
template<class T, char* p> class X {
// ...
X();
X(const char* q) { /* ... */ }
};
X<int,"Studebaker"> x1; // error: string literal as
template-argument
char p[] = "Vivisectionist";
X<int,p> x2; // OK
But remember that template type identity is based on argument identity,
and a compiler is free to unify character array constants if it can:
template <char* P> class X { /*...*/ };
char foo[] = "Foobar";
char bar[] = "Foobar";
Whether X<foo> and X<bar> are the same type is implementation defined.
--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"There are many technical details that make Linux attractive to the
sort of people to whom technical details are attractive." -- Suck
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/10/15 Raw View
Ross Smith wrote:
>
> Andy Glew wrote:
> >
> > I have a template class init<T,init_value> that, you guessed it,
> > allows an initial value to be specified in the declaration.
> >
> > I find it especially useful inside structures
> >
> > struct point {
> > init<float,0> x;
> > init<float,0> y;
> > };
> >
> > Although ) is my most common initial value, occasionally I like
> > using garbage values
> >
> > struct point {
> > init<float,-999.9999> x;
> > init<float,-86776.9879978> y;
> > };
> >
> > to increase the chance of catching an error. Of course, I also
> > have float_init_nan, double_init_nan for IEEE systems.
>
> Well, you can do that if you don't mind being limited to integral
> values, by simply casting the integer template argument to the floating
> point type inside the template.
>
> My graphics library has a Colour template that looks something like
> this:
>
> template <typename Channel, unsigned Unit> class Colour {
> // Channel = type used for the RGB channels
> // Unit = saturation value of a channel
> public:
> Colour(Channel r, Channel g, Channel b):
> red(r), green(g), blue(b) {}
> static Colour black() { return Colour(0, 0, 0); }
> static Colour white() { return Colour(Unit, Unit, Unit); }
> // ...
> private:
> Channel red;
> Channel green;
> Channel blue;
> };
> // Commonly used instantiations
> typedef Colour<unsigned char, 255> Colour24bit;
> typedef Colour<float, 1> FloatColour;
>
> > While we're at it, may I say that I can also imagine uses for string literals
> > as template parameters - e.g. specifying print_names.
> >
> > print_name<int,"Branch Misprediction Count"> bmpc;
> >
> > Actually, I would probably most like string template parameters so that
> > I can specify printf format strings to be used in printing, e.g. a value to cout.
> > However, I don't think that the standards committee would approve of that.
>
> Pointers can be template arguments. You can't use a string literal
> because template arguments must have external linkage, but that's easily
> fixed with one more line of code. This example comes directly from the
> Standard (14.3.2):
>
> template<class T, char* p> class X {
> // ...
> X();
> X(const char* q) { /* ... */ }
> };
> X<int,"Studebaker"> x1; // error: string literal as
> template-argument
> char p[] = "Vivisectionist";
> X<int,p> x2; // OK
>
> But remember that template type identity is based on argument identity,
> and a compiler is free to unify character array constants if it can:
>
> template <char* P> class X { /*...*/ };
> char foo[] = "Foobar";
> char bar[] = "Foobar";
>
> Whether X<foo> and X<bar> are the same type is implementation defined.
I don't think the compiler can unify foo and bar. It would
break the following code:
void foobar()
{
foo[0]='X';
bar[0]='Y';
assert(foo[0]=='X');
}
The compiler can unify string _literals_, so that with
char* foo2 = "Foobar";
char* bar2 = "Foobar";
both foo2 and bar2 may point to the same address. But I'm almost
sure that it cannot unify the arrays foo and bar.
Isn't exactly this the reason why string literals cannot be used
as template argument?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/10/14 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
> >Because he would otherwise have to define them separately?
> It is possible to define a static const int inside the class
> definition. Like this
> template <int lhs, int rhs>
> struct max { static const int result=lhs<rhs?rhs:lhs; };
It is still necessary to define 'result' separtately. See 9.4.2/4.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/14 Raw View
On 11 Oct 1999 17:38:21 GMT, Gabriel Dos_Reis
>sbnaran@uiuc.edu (Siemel B. Naran) writes:
>| template <int lhs, int rhs>
>| struct max { static const int result=lhs<rhs?rhs:lhs; };
>
>I said *define*.
>
>The above is a _declaration_
No, the above is a definition of class max<int,int>.
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/14 Raw View
On 14 Oct 99 08:04:43 GMT, Hyman Rosen <hymie@prolifics.com> wrote:
>sbnaran@uiuc.edu (Siemel B. Naran) writes:
>> It is possible to define a static const int inside the class
>> definition. Like this
>
>It is still necessary to define 'result' separtately. See 9.4.2/4.
Yes, the standard says that if the static const variable does not have
a definition outside the class, then the program is undefined. However,
a reasonable compiler will not require the definition outside the
class if there is a definition inside the class.
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/10/14 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
| On 11 Oct 1999 17:38:21 GMT, Gabriel Dos_Reis
| >sbnaran@uiuc.edu (Siemel B. Naran) writes:
|
| >| template <int lhs, int rhs>
| >| struct max { static const int result=lhs<rhs?rhs:lhs; };
| >
| >I said *define*.
| >
| >The above is a _declaration_
|
| No, the above is a definition of class max<int,int>.
Not of max<int, int>::result.
Must I remind you your initial question?
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/10 Raw View
On 10 Oct 99 03:20:55 GMT, Masao Morita <m-morita@pdss7.trc.rwcp.or.jp> wrote:
>Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
>I attempted the following:
>
>template<int n> struct fac { const int value = n*fac<n-1>::value; };
>template<> struct fac<0> { const int value = 0; };
>
>But a compiler that I use rejected. I also attempted the following:
Error in the above.
Class variables must be initialized in the constructor.
Static const integrals can be initialized in the class.
>template<int n> struct fac { static const int value = n*fac<n-1>::value; };
>template<> struct fac<0> { static const int value = 0; };
>
>The compiler accepted.
Yes, this second version is fine.
>> template<char const* Name> class X
>> {
>> public:
>> char const* name() { return Name; }
>> // ...
>> };
>class X
>{
> const char* Name;
>public:
> X(const char* nm) { Name = nm; }
> const char* name() { return Name; }
>};
BTW, it is wise to make the one-arg constructor explicit.
class X
{
const char *const Name;
public:
explicit X(const char* Name) : Name(Name) { }
const char* name() { return Name; }
};
But to get the same effect as Christopher's code, the Name data member
must be shared by all X objects. So it must be static.
class X
{
static const char *const Name;
public:
X() : Name(Name) { }
static const char* name() { return Name; }
};
>What sort of case is the former one is advantageous?
One reason is to enforce requirements. Say we have a function
f(X x1, X x2);
and we want x1.name() to be the same as x2.name(). To enforce
this constraint at compile we just do
template <const char * Name> class X { ... };
template <const char * Name> void f(X<Name> x1, X<Name> x2) { ... }
This is why I wanted the extraction iterators to be templated.
struct Struct { int field1; int field2; };
Then the compiler would flag this as an error
std::container<Struct> c;
std::for_each(
extract<&Struct::field1>(c.begin()),
extract<&Struct::field2>(c.end ()),
&some_action
);
But in the non-template version, the compiler will not catch the error
std::container<Struct> c;
std::for_each(
extract(c.begin(),&Struct::field1),
extract(c.end (),&Struct::field2),
&some_action
);
The template way also uses less stack space. In the non-template
version, class X holds Name as a private data member, so its sizeof
is increased. Incidentally, we can think of the stack as a
container. Then my previous assertion that a container of X<int>
objects will use less space than a container of X objects where the
int is a private data member of class X, holds true.
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/10 Raw View
On 10 Oct 99 03:21:17 GMT, James Kuyper Jr. <kuyper@wizard.net> wrote:
>"Siemel B. Naran" wrote:
>And it's perfectly plausible to want a function which is compile time
>constant on one parameter, and run-time variable on another. Simple
>example:
>
>template <size_t Degree> class Polynomial
>{
This is a template class, and I agree that it is useful.
One can think of certain template classes as like functions, but that's
just a metaphor.
But the question remains: what is the purpose of a real template
function as you wrote earlier?
One place where I've use template functions with non-type template
parameters is to seperate the arguments to the function for
greater program understanding. Example:
template <bool Debug, class Function>
double rootfind(Function, double a, double b);
Then we can say
cout << rootfind<false>(Cosine(1.0),0.0,3.0);
I think that the above looks more clear than
cout << rootfind(Cosine(1.0),0.0,3.0,false);
The "false" in the function argument list may confuse some readers
because they wonder how it will affect the root found. But the
"false" in the template argument list is less confusing because it
seems clear that this boolean has little or nothing to do with the
actual rootfinding.
>> BTW, what is the reason that we can't have double as a template
>> parameter?
>
>Because equality comparison of double values is inherently tricky. You
>probably don't want your compiler instantiating two different templates,
>one for 1.9999999999..., and a different one for 2.00000... .
>Also, just by their very nature, doubles are a discrete approximation to
>something that is conceptually continuous. You generally want to cope
>with continuous variables continuously. Templates allow different but
>related code to be defined for a large but discrete set of different
>cases.
Just imagine this
template <double x>
void f(X<x> x1, X<x> x2);
int main() { f( X<1.0>() , X<1.0/3.0*3.0>() ); }
Does this instantiate
f<1.0>(X<1.0>);
or does it it generate a compile error because the call is to
void f(X<1.0>, X<0.999999999>);
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/10/11 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
| On 09 Oct 99 05:35:15 GMT, Gabriel Dos_Reis <gdosreis@korrigan.inria.fr> wrote:
| >sbnaran@uiuc.edu (Siemel B. Naran) writes:
|
| >| Any reason why you are using enums rather than static const int?
| >
| >Because he would otherwise have to define them separately?
|
| It is possible to define a static const int inside the class
| definition. Like this
|
| template <int lhs, int rhs>
| struct max { static const int result=lhs<rhs?rhs:lhs; };
I said *define*.
The above is a _declaration_
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/09 Raw View
On 8 Oct 1999 17:07:06 GMT, Christopher Eltschka
>Martin Aupperle wrote:
>> On 30 Sep 99 12:38:36 GMT, James Kuyper <kuyper@wizard.net> wrote:
>>>It is legal. One example of possible use:
>>>
>>> template<int i> int Add(int j) { return i+j; }
>>>
>>>This seems trivial, but it could be useful. More complicated
>>>possibilities get very interesting.
>> Can you give an example of such possibilities? (I'm kind of new to
>> template metaprogramming and want to learn)
>
>One "standard" example is calculating the faculty of a
>number at compile time:
>
>template<int n> struct fac { enum { value = n*fac<n-1>::value; }; };
>template<> struct fac<0> { enum { value = 1; }; };
Any reason why you are using enums rather than static const int?
But can you think of an example where a template function that takes
one argument as a template parameter and another as a function
argument, is useful. Sure, there are uses for template classes like
your one above. Incidentally, we can think of struct fac<int> as a
function whose result is a compile time constant. But real template
functions, especially those which take some template arguments and
some function arguments, I can't find a practical use for them.
Another useful one is struct max<int,int> so we can do
char empty[max<sizeof(A),sizeof(B)>::result];
This is useful if we want an object AB that is either an A or a B.
Then sizeof(AB) should be the larger of sizeof(A) and sizeof(B).
The above 'empty' becomes a private member of class AB. We also
need to worry about alignment, which drives me crazy.
I've also wanted to calculate log10 as a compile time constant so
that I can create a char[] array of just the right length
char text[log10<int>::result];
My function converts an int into its textual representation, so to
save space I want a char[] array of just the right length. Maybe
there are better ways to do this; let me know.
>You could also do things like gcd:
>int array[gcd<12,15>]; // array of 3 ints
The question is why :).
>You can also use boolean predicates to select types:
>
>template<bool condition, class T1, class T2> struct select
>{
> typedef T1 type;
>};
>
>template<class T1, class T2> struct select<false, T1, T2>
>{
> typedef T2 type;
>};
Kind of like
typedef condition?T1:T2 type;
I wish C++ supported the conditional operator on types, because
it is so much easier to use.
>Well, the examples above nearly all use partial specialisation.
>I'm not sure if it is also allowed on functions, but if it is,
>an example could be:
>
>template<int n> double power(double x)
>{
> double retval=1;
> for (int i=0; i<n; ++i) retval*=x;
> return retval;
>}
Impractical. Most likely 'n' is a double, or 'n' is known only at
runtime or is part of a for loop (but we can make a template for
loop), and the above may be too slow.
BTW, what is the reason that we can't have double as a template
parameter?
>Now it's obvious that for n=0, the value is 1 anyway, so we
>could specialize:
>
>template<> double power<0>(double x)
>{
> return 1;
>}
>
>In this case, since n is known at compile time, a good compiler
>should do that optimisation anyway; however for more complex
>calculations, this might not be true anymore.
Most likely if function power is inline.
>extern char const foo[] = "foo";
>extern char const bar[] = "bar";
>
>template<char const* Name> class X
>{
>public:
> char const* name() { return Name; }
> // ...
>};
>
>int main()
>{
> X<foo> x;
> X<bar> y;
> std::cout << x.name() << ", " << y.name() << std::endl;
>}
>
>This should print "foo, bar".
>
>Something like this might be useful for persistence libraries.
What are you talking about?
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/10/09 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
| On 8 Oct 1999 17:07:06 GMT, Christopher Eltschka
| >Martin Aupperle wrote:
| >> On 30 Sep 99 12:38:36 GMT, James Kuyper <kuyper@wizard.net> wrote:
|
| >>>It is legal. One example of possible use:
| >>>
| >>> template<int i> int Add(int j) { return i+j; }
| >>>
| >>>This seems trivial, but it could be useful. More complicated
| >>>possibilities get very interesting.
|
| >> Can you give an example of such possibilities? (I'm kind of new to
| >> template metaprogramming and want to learn)
| >
| >One "standard" example is calculating the faculty of a
| >number at compile time:
| >
| >template<int n> struct fac { enum { value = n*fac<n-1>::value; }; };
| >template<> struct fac<0> { enum { value = 1; }; };
|
| Any reason why you are using enums rather than static const int?
Because he would otherwise have to define them separately?
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ross Smith <ross.s@ihug.co.nz>
Date: 1999/10/09 Raw View
"Siemel B. Naran" wrote:
>
> BTW, what is the reason that we can't have double as a template
> parameter?
It would make type identity ambiguous. Consider:
template <double D> class Foobar { /*...*/ };
typedef Foobar<1.00000000001> Foo;
typedef Foobar<1.00000000002> Bar;
(NB. The standard requires double to have at least 10 decimal digits of
resolution; the common IEC/IEEE 64-bit implementation has 15.)
Are Foo and Bar the same type? What happens of I try to overload a
function on Foo vs Bar arguments? What if I'm using a cross-compiler,
and the compilation and target systems have different floating point
hardware?
Disallowing FP template arguments is just a special case of the general
principle adopted by the C and C++ committees (largely, I gather, in
response to the cross compilation problem) that the compiler must not be
required to do FP arithmetic at compile time.
--
Ross Smith <ross.s@ihug.co.nz> The Internet Group, Auckland, New Zealand
========================================================================
"There are many technical details that make Linux attractive to the
sort of people to whom technical details are attractive." -- Suck
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Masao Morita <m-morita@pdss7.trc.rwcp.or.jp>
Date: 1999/10/10 Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> writes:
> template<int n> struct fac { enum { value = n*fac<n-1>::value; }; };
> template<> struct fac<0> { enum { value = 1; }; };
I sometimes look such a example. But I think it is not good for readablity.
Here "value" represents an integral value, not a enumuration one which has
the other usage.
I attempted the following:
template<int n> struct fac { const int value = n*fac<n-1>::value; };
template<> struct fac<0> { const int value = 0; };
But a compiler that I use rejected. I also attempted the following:
template<int n> struct fac { static const int value = n*fac<n-1>::value; };
template<> struct fac<0> { static const int value = 0; };
The compiler accepted.
Is the former one illegal? and Is the latter one legal? according to the
standard.
> BTW, one other possibility of non-type template parameters:
>
> extern char const foo[] = "foo";
> extern char const bar[] = "bar";
>
> template<char const* Name> class X
> {
> public:
> char const* name() { return Name; }
> // ...
> };
>
> int main()
> {
> X<foo> x;
> X<bar> y;
> std::cout << x.name() << ", " << y.name() << std::endl;
> }
Thank you for an example.
I am now little bit clear for the case of which is a pointer of an object.
But I think it is not so good. I like the following:
class X
{
const char* Name;
public:
X(const char* nm) { Name = nm; }
const char* name() { return Name; }
};
int main()
{
X x(foo);
X y(bar);
...
}
What sort of case is the former one is advantageous?
M.Morita
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: 1999/10/10 Raw View
"Siemel B. Naran" wrote:
>
> On 8 Oct 1999 17:07:06 GMT, Christopher Eltschka
> >Martin Aupperle wrote:
....
> >template<int n> struct fac { enum { value = n*fac<n-1>::value; }; };
> >template<> struct fac<0> { enum { value = 1; }; };
>
> Any reason why you are using enums rather than static const int?
In my similar example, it was because the compiler I was using was not
fully conforming, in that it didn't handle static const ints correctly
in this regard.
> But can you think of an example where a template function that takes
> one argument as a template parameter and another as a function
> argument, is useful. Sure, there are uses for template classes like
> your one above. Incidentally, we can think of struct fac<int> as a
> function whose result is a compile time constant. But real template
And it's perfectly plausible to want a function which is compile time
constant on one parameter, and run-time variable on another. Simple
example:
template <size_t Degree> class Polynomial
{
private:
const double coefficients[Degree+1];
public:
template <class ForwardIterator> Polynomial(ForwardIterator i)
{
for(size_t n=0; n<=Degree; n++)
coefficients[n] = *i;
}
double operator() (double x) const
{
double retval = coefficient[Degree+1];
for(size_t n=Degree; n; n--)
retval = retval*x + coefficient[n];
return retval;
}
};
....
> >template<int n> double power(double x)
> >{
> > double retval=1;
> > for (int i=0; i<n; ++i) retval*=x;
> > return retval;
> >}
>
> Impractical. Most likely 'n' is a double, or 'n' is known only at
'n' is a counter; it's unlikely to be a double.
> runtime or is part of a for loop (but we can make a template for
> loop), and the above may be too slow.
In many cases, 'n' is small and fixed at compile time. When that isn't
true, std::pow() is of course the appropriate thing to use.
> BTW, what is the reason that we can't have double as a template
> parameter?
Because equality comparison of double values is inherently tricky. You
probably don't want your compiler instantiating two different templates,
one for 1.9999999999..., and a different one for 2.00000... .
Also, just by their very nature, doubles are a discrete approximation to
something that is conceptually continuous. You generally want to cope
with continuous variables continuously. Templates allow different but
related code to be defined for a large but discrete set of different
cases.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/10 Raw View
On 09 Oct 99 05:35:15 GMT, Gabriel Dos_Reis <gdosreis@korrigan.inria.fr> wrote:
>sbnaran@uiuc.edu (Siemel B. Naran) writes:
>| Any reason why you are using enums rather than static const int?
>
>Because he would otherwise have to define them separately?
It is possible to define a static const int inside the class
definition. Like this
template <int lhs, int rhs>
struct max { static const int result=lhs<rhs?rhs:lhs; };
Other threads on various newsgroups tell me that MSVC does not support
static const int defined inside the class, so then one uses enum. But
still, I think that static const int is better.
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: MikeAlpha@NoSpam_csi.com (Martin Aupperle)
Date: 1999/10/08 Raw View
On 30 Sep 99 12:38:36 GMT, James Kuyper <kuyper@wizard.net> wrote:
>
>It is legal. One example of possible use:
>
> template<int i> int Add(int j) { return i+j; }
>
>This seems trivial, but it could be useful. More complicated
>possibilities get very interesting.
>
Can you give an example of such possibilities? (I'm kind of new to
template metaprogramming and want to learn)
[snip]
>
>Another possibility is to provide two 'int' template parameters, and
>provide a partial specialization for the case where they're equal.
>
Can you give me a hint how to write such a thing?
Thanks - Martin
------------------------------------------------
Martin Aupperle
MikeAlpha@NoSpam_csi.com
(remove NoSpam_)
------------------------------------------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/10/08 Raw View
Martin Aupperle wrote:
>
> On 30 Sep 99 12:38:36 GMT, James Kuyper <kuyper@wizard.net> wrote:
>
> >
> >It is legal. One example of possible use:
> >
> > template<int i> int Add(int j) { return i+j; }
> >
> >This seems trivial, but it could be useful. More complicated
> >possibilities get very interesting.
> >
> Can you give an example of such possibilities? (I'm kind of new to
> template metaprogramming and want to learn)
One "standard" example is calculating the faculty of a
number at compile time:
template<int n> struct fac { enum { value = n*fac<n-1>::value; }; };
template<> struct fac<0> { enum { value = 1; }; };
int array[fac<5>::value]; // array of 120 ints
You could also do things like gcd:
template<int a, int b> struct gcd
{ enum { value = gcd<b, a%b>::value }; };
template<> struct gcd<a,0> { enum { value = a }; };
int array[gcd<12,15>]; // array of 3 ints
You can also use boolean predicates to select types:
template<bool condition, class T1, class T2> struct select
{
typedef T1 type;
};
template<class T1, class T2> struct select<false, T1, T2>
{
typedef T2 type;
};
Now assume that on your platform it is more efficient to pass
objects with sizeof T <= 4 by value, but larger ones by reference.
Then you could use that in a template class like this:
template<class T> class Foo
{
public:
void f(typename select<(sizeof(T)<=4), T, T const&>::type x);
};
Now, if instantiated on int (assuming sizeof int <= 4), you'll
get:
void Foo<int>::f(int x);
while for Big (with sizeof Big > 4), you get
void foo<Big>::f(Big const& x);
Another useful trick is using references to arrays to get some info
on types through the compiler overloading mechanism:
template<int n, class T1, class T2, class T3> struct select3;
template<class T1, class T2, class T3>
struct select3<1, T1, T2, T3> { typedef T1 type; }
template<class T1, class T2, class T3>
struct select3<2, T1, T2, T3> { typedef T2 type; }
template<class T1, class T2, class T3>
struct select3<2, T1, T2, T3> { typedef T3 type; }
char (&type_check(foo*))[1];
char (&type_check(bar*))[2];
char (&type_check(void*))[3];
template<class T> class Foobar
{
typedef typename select3<sizeof(type_check((T*)0)),
Foo1, Foo2, Foo3>:: type Footype;
// ...
};
Here Footype is Foo1 if T is derived from foo, Foo2 if T
is derived from bar, and Foo3 otherwise.
The trick is that the size of the return value depends on
the function chosen. Since the size is computed at compile
time, it can itself be used as template parameter for
select3.
Something like this can be used to make desicions based
on automatically derived features of a type or expression
(unfortunately the features that can be tested this way are
quite limited).
>
> [snip]
> >
> >Another possibility is to provide two 'int' template parameters, and
> >provide a partial specialization for the case where they're equal.
> >
> Can you give me a hint how to write such a thing?
Well, the examples above nearly all use partial specialisation.
I'm not sure if it is also allowed on functions, but if it is,
an example could be:
template<int n> double power(double x)
{
double retval=1;
for (int i=0; i<n; ++i) retval*=x;
return retval;
}
Now it's obvious that for n=0, the value is 1 anyway, so we
could specialize:
template<> double power<0>(double x)
{
return 1;
}
In this case, since n is known at compile time, a good compiler
should do that optimisation anyway; however for more complex
calculations, this might not be true anymore.
BTW, one other possibility of non-type template parameters:
extern char const foo[] = "foo";
extern char const bar[] = "bar";
template<char const* Name> class X
{
public:
char const* name() { return Name; }
// ...
};
int main()
{
X<foo> x;
X<bar> y;
std::cout << x.name() << ", " << y.name() << std::endl;
}
This should print "foo, bar".
Something like this might be useful for persistence libraries.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/10/08 Raw View
Martin Aupperle wrote:
>
> On 30 Sep 99 12:38:36 GMT, James Kuyper <kuyper@wizard.net> wrote:
>
> >
> >It is legal. One example of possible use:
> >
> > template<int i> int Add(int j) { return i+j; }
> >
> >This seems trivial, but it could be useful. More complicated
> >possibilities get very interesting.
> >
> Can you give an example of such possibilities? (I'm kind of new to
> template metaprogramming and want to learn)
I'm new too, but here's a non-type template parameter example I've
actually used:
template <unsigned long N> class comp_func{
public:
enum {
// smallest integral power of 2 greater than sqrt(N):
sqrt_power2 = N<4 ? 1 : 2*comp_func<N/4>::sqrt_power2
};
};
// Needed to terminate recursion; even though above template never uses
// comp_func<0>, it does refer to it when N<4.
class comp_func<0> {
public:
enum {sqrt_power2 = 1};
};
> >Another possibility is to provide two 'int' template parameters, and
> >provide a partial specialization for the case where they're equal.
> >
> Can you give me a hint how to write such a thing?
>
> Thanks - Martin
template <int i, int j>
class invert(const double in[i][j], double out[j][i])
{
// Calculates one of the infinitly many possible values for 'out'
// that satisfy matrix_multiply(in,out) == identity matrix.
// Rather complicated for i!=j.
};
template < int i>
class invert<i,i>(const double in[i][i], double out[i][i])
{
// Make 'out' be the unique inverse matrix of 'in'.
// Somewhat simpler.
};
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/05 Raw View
On 4 Oct 1999 16:04:05 GMT, Masao Morita <m-morita@pdss7.trc.rwcp.or.jp> wrote:
>sbnaran@uiuc.edu (Siemel B. Naran) writes:
> template<int n, class T, T* dest, T* source>
> void arr_copy(dest, source) { for(int i=0;i>n;i++) { *dest++ = *source++; } }
Syntax error.
Non-type template arguments cannot appear in the function argument list.
>>A non-template parameter shall have one of the following(14.1.p4):
>>
>>1) integral or enumeration type
>>2) pointer to object or pointer to function
>>3) reference to object or pointer to function,
>>4) pointer to member
I thought there was a
5) template class -- eg,
template <template <class T> class X> struct Silly { X<int> x; };
template <class T> class container { T d_data[10]; };
int main() { Silly<container> s; }
>I already understood 1) is pretty good for practical usages.
Yes, Christopher had some fine examples.
>But 2)3)4) are not clear in my mind.
There's really not much use for them.
I once wrote templated extractor:
template <class Struct, typename T, T Struct::*field>
struct extract
{
typedef Struct & argument_type;
typedef T & result_type ;
result_type operator()(argument_type arg) const { return arg.*field; }
};
One would use it like this
struct X { int x1; double x2; }
int main()
{
extract e<X,double,&X::x2>;
X x={1,2.0};
cout << e(x) << '\n'; // print "2"
}
My intent was to use extractors like the above to write extraction
iterators. This is an iterator whose operator* returns not a
reference to the whole struct but rather a reference to a field
in the struct. I guess it would go something like this --
template <class Iter, class T, T (typename Iter::value_type)::*field>
class extract_iterator_t
{
public:
typedef T& reference;
explicit extract_iterator_t(Iter iter) : iter(iter) { }
reference operator*() const { return *iter.*field; }
extract_iterator_t& operator++() { ++iter; return *this; }
const extract_iterator_t operator++(int);
private:
Iter iter;
};
However, the first line is illegal. Template argument lists can't be
too complicated. So we have to use instead
template <class Iter, class Struct, class T, T Struct::*field>
Then we have to hope that Iter::value_type is the same as Struct.
Because it tedious to specify template arguments when we create a
extract_iterator_t object, we write a non-member function. Non-member
functions make use of template argument deduction. We may think of
these non-member functions as constructors.
template <class Iter, class Struct, class T, T Struct::*field>
extract_iterator_t<Iter,Struct,T,field>
extract_iterator(Iter iter)
{
return extract_iterator_t<Iter,Struct,T,field>(iter);
}
And we would use it like this
struct X { int x1; double x2; }
int main()
{
std::container<X> c;
typedef extract_iterator<&X::x2> Iter; // LINE2
std::for_each(Iter(c.begin()),Iter(c.end()),Action());
}
Unfortunately, LINE2 of main() is an error because we must specify
all template arguments. As this is so tedious to do, I gave up
on these templated extraction iterators.
typedef extract_iterator<std::container::iterator,X,double,&X::x2> Iter;
Previously, I asked if there was a way to have template argument
deduction deduce the first three template parameters, and we only
supply the fourth in the template argument list. Alas there is
no such way.
>The current standard was enlarged for non-type template parameters.
>Maybe, There are people who insist on the need for the addtion 2)3)4).
Well, I can't think of any practical uses.
--
--------------
siemel b naran
--------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Masao Morita <m-morita@pdss7.trc.rwcp.or.jp>
Date: 1999/10/06 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
> > template<int n, class T, T* dest, T* source>
> > void arr_copy(dest, source) { for(int i=0;i>n;i++) { *dest++ = *source++; } }
>
> Syntax error.
The complier that I use says so. but,,,
> Non-type template arguments cannot appear in the function argument list.
Really?, I can not find such a restriction in the standard.
More over, a non-type template argument appear
Christopher Eltschka wrote:
>template<class T, int n>
>void arr_copy(T const (&source)[n], T (&dest)[n])
>{ for (int i=0; i<n; ++i) dest[i]=source[i]; }
This makes the instantiated function from the function call like
"arr_copy(a,b)".
I suspect that the compiler does not support only in a case where a non-type
template parameter is a pointer of an object.
But I might miss the restriction anywhere in the standard.
Please let me konw where is the exact explanation about this in the standard.
> >>A non-template parameter shall have one of the following(14.1.p4):
> >>
> >>1) integral or enumeration type
> >>2) pointer to object or pointer to function
> >>3) reference to object or pointer to function,
> >>4) pointer to member
>
> I thought there was a
> 5) template class -- eg,
> template <template <class T> class X> struct Silly { X<int> x; };
> template <class T> class container { T d_data[10]; };
> int main() { Silly<container> s; }
The standard says 14.1.p9
|....
| default template-argument may be specified for any kind of template parameter
| (type,non-type,template). ...
I think the standard classify the template parameter under three types.
a) type parameter
b) non-type parameter
c) template parameter
So, template classes is not a non-type parameter.
Of cource, I know the template template argument is very useful.
> I once wrote templated extractor:
>
> template <class Struct, typename T, T Struct::*field>
> struct extract
> {
> typedef Struct & argument_type;
> typedef T & result_type ;
> result_type operator()(argument_type arg) const { return arg.*field; }
> };
>
> One would use it like this
>
> struct X { int x1; double x2; }
> int main()
> {
> extract e<X,double,&X::x2>;
> X x={1,2.0};
> cout << e(x) << '\n'; // print "2"
> }
Thank you for showing me an example!
> My intent was to use extractors like the above to write extraction
> iterators. This is an iterator whose operator* returns not a
> reference to the whole struct but rather a reference to a field
> in the struct. I guess it would go something like this --
[snip] sorry.
> Previously, I asked if there was a way to have template argument
> deduction deduce the first three template parameters, and we only
> supply the fourth in the template argument list. Alas there is
> no such way.
I understand your intention. it is interesting!
But I have no good idea about that.
> >The current standard was enlarged for non-type template parameters.
> >Maybe, There are people who insist on the need for the addtion 2)3)4).
>
> Well, I can't think of any practical uses.
I am waiting for ... for some time.
M. Morita
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/07 Raw View
On 6 Oct 1999 06:53:37 GMT, Masao Morita <m-morita@pdss7.trc.rwcp.or.jp> wrote:
>sbnaran@uiuc.edu (Siemel B. Naran) writes:
>> Non-type template arguments cannot appear in the function argument list.
>Really?, I can not find such a restriction in the standard.
The function argument list is of the form
void f(T1 t1, T2 t2, T3 t3);
't1' is an object of type T1.
't2' is an object of type T2.
't3' is an object of type T3.
Obviously, T1 and T2 and T3 must be the names of types. In your
previous example, T1 and T2 were values. This doesn't make sense.
> template<int n, class T, T* dest, T* source>
> void arr_copy(dest, source) { for(int i=0;i>n;i++) { *dest++ = *source++; } }
>More over, a non-type template argument appear
>Christopher Eltschka wrote:
>>template<class T, int n>
>>void arr_copy(T const (&source)[n], T (&dest)[n])
>>{ for (int i=0; i<n; ++i) dest[i]=source[i]; }
Sorry, I forgot about this. Non-type template arguments may appear
as part of the type, as in array sizes.
--
--------------
siemel b naran
--------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Masao Morita <m-morita@pdss7.trc.rwcp.or.jp>
Date: 1999/10/04 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
> >I am just wondering the following is a one of practical usages?
> >
> > template<class T, T* source, T* dest, int n = 10>
> > void arr_copy(source,dest) { ... }
>
> IMHO, this is not a practical usage.
>
> First, it is more cumbersome to type. One must say
> arr_copy<int,&target,&source,10>();
> But it is more natural to say
> arr_copy(target,source);
My example is not appropiate as you said.
How about the following:
template<int n, class T, T* dest, T* source>
void arr_copy(dest, source) { for(int i=0;i>n;i++) { *dest++ = *source++; } }
int target[5];
const int src[5]= {1,2,3,4,5};
main() {
arr_copy<5>(target,src); // #1
}
I suppose #1 would be a legal call by means of the argument deduction.
Is this right? (according to the standard)
[By the way, does the compiler apply the standard conversion on the
non-type template parameter which is a pointer of an object?
If the array-to-pointer conversion does not apply, #1 should be
"arr_copy<5>(&target[0],&src[0])".]
> Second, the address of the template parameters "source" or "dest"
> must be integral constants known at compile time. This means that
> the following is legal --
>
> int target[5];
> const int source[5]={1,2,3,4,5};
> int main() {
> arr_copy<int,&target,&source,5>(); // ok
> // ok: &target, &source known at compile time
> }
>
> but the following is not
>
> int main() {
> int target[5];
> const int source[5]={1,2,3,4,5};
> arr_copy<int,&target,&source,5>(); // error
> // error: &target, &source not known at compile time
> }
This is a case of the explicit template parameter. But, in case of the
argument deduction, does such a restriction, too?
Even though the above #1 is OK, the following is illegal?
main() {
const int src[5]= {1,2,3,4,5};
int target[5];
arr_copy<5>(target,src);
}
> One of the practical uses of classes using non-type template
> parameters is to reduce the size of the class. Consider the
> following:
>
> class shift {
> public:
> explicit shift(int s) : s(s) { }
> int operator()(int x) const { return s+x; }
> private:
> const int s;
> };
>
> sizeof(shift) is sizeof(int). Now consider the following:
>
> template <class s>
> class shift {
> public:
> shift() { }
> int operator()(int x) const { return s+x; }
> };
>
> In the second version, sizeof(shift) is sizeof(empty).
>
> Well, it's not like we're going to have an array of shift objects,
> so does this advantage really matter?
I agree. but, I guess the latter one is "template <int s>" not
"template <class s>".
The standard says,
>A non-template parameter shall have one of the following(14.1.p4):
>
>1) integral or enumeration type
>2) pointer to object or pointer to function
>3) reference to object or pointer to function,
>4) pointer to member
I already understood 1) is pretty good for practical usages.
But 2)3)4) are not clear in my mind.
The current standard was enlarged for non-type template parameters.
Maybe, There are people who insist on the need for the addtion 2)3)4).
If possible, please show me reasons or examples.
M. Morita
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Masao Morita <m-morita@pdss7.trc.rwcp.or.jp>
Date: 1999/10/01 Raw View
I wrote:
> > In class template,
> > template <class T, int Size = 10> class MyArray {
> > T Arr[Size];
> > ...
> > };
Christopher Eltschka wrote:
> template<int i> void foo(MyArray<int, i>& a) { ... }
Oops! Thank you.
I understand that if there is a useful example in template class,
there is a useful one in function template, too. A function which
has a argument of its template class makes sense.
> template<class T, int n>
> void arr_copy(T const (&source)[n], T (&dest)[n])
> {
> for (int i=0; i<n; ++i)
> dest[i]=source[i];
> }
Thanks for a nice example without a template class.
When a non-type template parameter is a pointer to object,
I am just wondering the following is a one of practical usages?
template<class T, T* source, T* dest, int n = 10>
void arr_copy(source,dest) { ... }
M. Morita
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/10/01 Raw View
"Siemel B. Naran" wrote:
>
> On 30 Sep 99 12:38:36 GMT, James Kuyper <kuyper@wizard.net> wrote:
...
> >One powerful option is a Bool function template parameter, with the
> >template having two different specializations; one for 'true' and the
> >other for 'false'. You can select which one to use at compile time based
> >upon any constant relational expression, such as 'INT_MAX>SHRT_MAX'. In
> >some cases this produces clearer code than #if, and possibilities for
> >better optimization than if().
>
> I'm skeptical of the use this technique, in particular that it may
> produce code that is easier to read. Don't forgot to mention the
> one disadvantage of this code: the compiler has to compiler template
> code that it might never use, which makes compiling slow. A second
It may need to compile it, but if it's never used, it won't need to
instantiate it. Can you provide an alternative technique that skips the
need to compile both options, despite the fact that there is no way of
knowing at the time they're compiled which one will be used?
A typical example I'm thinking of is one that chooses radically
implementations of the same algorithm, depending upon a traits class
property.
> disadvantage: the code tends to look a little cryptic with this
> funny additional Bool parameter, which might have a bizarre default
> value.
I'm the designer; it won't have a bizarre default value unless I decide
that it should. The 'funny additional Bool parameter' needn't be
cryptic, if given a suitable name.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/10/02 Raw View
On 01 Oct 99 17:55:03 GMT, Masao Morita <m-morita@pdss7.trc.rwcp.or.jp> wrote:
>I am just wondering the following is a one of practical usages?
>
> template<class T, T* source, T* dest, int n = 10>
> void arr_copy(source,dest) { ... }
IMHO, this is not a practical usage.
First, it is more cumbersome to type. One must say
arr_copy<int,&target,&source,10>();
But it is more natural to say
arr_copy(target,source);
Second, the address of the template parameters "source" or "dest"
must be integral constants known at compile time. This means that
the following is legal --
int target[5];
const int source[5]={1,2,3,4,5};
int main() {
arr_copy<int,&target,&source,5>(); // ok
// ok: &target, &source known at compile time
}
but the following is not
int main() {
int target[5];
const int source[5]={1,2,3,4,5};
arr_copy<int,&target,&source,5>(); // error
// error: &target, &source not known at compile time
}
One of the practical uses of classes using non-type template
parameters is to reduce the size of the class. Consider the
following:
class shift {
public:
explicit shift(int s) : s(s) { }
int operator()(int x) const { return s+x; }
private:
const int s;
};
sizeof(shift) is sizeof(int). Now consider the following:
template <class s>
class shift {
public:
shift() { }
int operator()(int x) const { return s+x; }
};
In the second version, sizeof(shift) is sizeof(empty).
Well, it's not like we're going to have an array of shift objects,
so does this advantage really matter?
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/30 Raw View
On 30 Sep 99 12:38:36 GMT, James Kuyper <kuyper@wizard.net> wrote:
>Masao Morita wrote:
>> 1) integral or enumeration type
>It is legal. One example of possible use:
>
> template<int i> int Add(int j) { return i+j; }
>
>This seems trivial, but it could be useful. More complicated
>possibilities get very interesting.
How can the above be useful?
The following can be useful because it allows us to calculate
max(a,b) as an integral constant. Note that both 'a' and 'b'
are template parameters. But in your example above, only 'a'
is a template parameter, so I don't know how your example
could be useful.
template <int lhs, int rhs>
struct max { const int result=lhs<rhs?rhs:lhs; };
And to use
int main() {
char empty[max<sizeof(A),sizeof(B)>::result];
}
>One powerful option is a Bool function template parameter, with the
>template having two different specializations; one for 'true' and the
>other for 'false'. You can select which one to use at compile time based
>upon any constant relational expression, such as 'INT_MAX>SHRT_MAX'. In
>some cases this produces clearer code than #if, and possibilities for
>better optimization than if().
I'm skeptical of the use this technique, in particular that it may
produce code that is easier to read. Don't forgot to mention the
one disadvantage of this code: the compiler has to compiler template
code that it might never use, which makes compiling slow. A second
disadvantage: the code tends to look a little cryptic with this
funny additional Bool parameter, which might have a bizarre default
value.
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/30 Raw View
On 30 Sep 99 12:39:02 GMT, Christopher Eltschka
>Masao Morita wrote:
>> I have some questions about a non-type template parameter.
>> A non-type template parameter was extended in the current standard from
>> the ARM. Probably there are some reasons for various non-type template
>> parameters. I would like to know the reasons.
>template<class T, int i, int j, int k>
> Matrix<T,i,k> operator*(Matrix<T,i,j> const& m1,
> Matrix<T,j,k> const& m2)
Good. Enforce some constraints at compile time.
I think the most useful non-type template parameter is
template template parameters. Eg,
template <class T, template <class T> class A>
class container;
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/09/30 Raw View
Masao Morita wrote:
...
> I have some questions about a non-type template parameter.
> A non-type template parameter was extended in the current standard from
> the ARM. Probably there are some reasons for various non-type template
> parameters. I would like to know the reasons.
>
> I try to consider each types.
>
> 1) integral or enumeration type
...
> On the other hand, in function template,
>
> template<int i = 10> void foo(i) { ... }
>
> [It is not good. I also suspect it is legal or not?] Even if OK,
> I think that using a general function is better rather than the
> template function, because of simplicity. As the following:
It is legal. One example of possible use:
template<int i> int Add(int j) { return i+j; }
This seems trivial, but it could be useful. More complicated
possibilities get very interesting.
> In case of using the template parameter in a function body.
>
> template<int i = 10> void foo() { /* using i as a global variable */ }
I'm not sure exactly how you mean this, but the template parameter is a
constant expression; it's not something you could store a value in. That
may prevent what you're thinking about.
One powerful option is a Bool function template parameter, with the
template having two different specializations; one for 'true' and the
other for 'false'. You can select which one to use at compile time based
upon any constant relational expression, such as 'INT_MAX>SHRT_MAX'. In
some cases this produces clearer code than #if, and possibilities for
better optimization than if().
Another possibility is to provide two 'int' template parameters, and
provide a partial specialization for the case where they're equal.
The other cases you mentioned get esoteric, but the general answer is
yes - there are cases where virtually any legal kind of non-type
template parameter could be useful. Just let the fact that it's possible
seep into your brain; eventually you'll find possible uses springing up
all over the place.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/09/30 Raw View
Masao Morita wrote:
>
> Thanks to this NG supporter for tactful advices.
>
> A template is a class or a function which is parameterized by parameters.
> I know it is very useful. It makes the source code short preserving type
> safe.
>
> I have some questions about a non-type template parameter.
> A non-type template parameter was extended in the current standard from
> the ARM. Probably there are some reasons for various non-type template
> parameters. I would like to know the reasons.
>
> I try to consider each types.
>
> 1) integral or enumeration type
>
> In class template,
>
> template <class T, int Size = 10> class MyArray {
> T Arr[Size];
> ...
> };
>
> [The size of Arr will be determined at the instantiation time of the use.]
> I think this is a good parameterized class and plausible template usage.
> In case of parameterizing enumeration type, it is useful to some degree.
>
> On the other hand, in function template,
>
> template<int i = 10> void foo(i) { ... }
>
> [It is not good. I also suspect it is legal or not?]
No, that's not legal. However, the following is:
template<int i> void foo(MyArray<int, i>& a) { ... }
[...]
> Is there a useful usage using a function template?
See above. Also:
template<class T, int i, int j, int k>
Matrix<T,i,k> operator*(Matrix<T,i,j> const& m1,
Matrix<T,j,k> const& m2)
{
...
}
This ensures that you can multiply a 2x3 matrix with a 3x4 matrix,
and get a 2x4 matrix, but multiplying a 2x3 matrix with a 3x5 matrix
is an error.
Or:
template<class T, int i>
T det(Matrix<T,i,i> const& m);
This allows only determinants of quadratic matrices (as it should
be, of course).
A nice special case is the following:
template<class T, int n>
void arr_copy(T const (&source)[n], T (&dest)[n])
{
for (int i=0; i<n; ++i)
dest[i]=source[i];
}
Now if you have
int foo[5];
int bar[5];
you can copy foo into bar with "arr_copy(foo, bar);" - the size
of the arrays is determined by the compiler (and checked that
both are the same size).
[...]
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Masao Morita <m-morita@pdss7.trc.rwcp.or.jp>
Date: 1999/09/29 Raw View
Thanks to this NG supporter for tactful advices.
A template is a class or a function which is parameterized by parameters.
I know it is very useful. It makes the source code short preserving type
safe.
I have some questions about a non-type template parameter.
A non-type template parameter was extended in the current standard from
the ARM. Probably there are some reasons for various non-type template
parameters. I would like to know the reasons.
I try to consider each types.
1) integral or enumeration type
In class template,
template <class T, int Size = 10> class MyArray {
T Arr[Size];
...
};
[The size of Arr will be determined at the instantiation time of the use.]
I think this is a good parameterized class and plausible template usage.
In case of parameterizing enumeration type, it is useful to some degree.
On the other hand, in function template,
template<int i = 10> void foo(i) { ... }
[It is not good. I also suspect it is legal or not?] Even if OK,
I think that using a general function is better rather than the
template function, because of simplicity. As the following:
void foo(int i = 10) { ... }
In case of using the template parameter in a function body.
template<int i = 10> void foo() { /* using i as a global variable */ }
In this case, a programmer should write the following at the function call.
foo<globalIntVariable>();
I think using a general function with an argument is the better choice too.
Surely there are some difference. In case of the function template, the
overload resolution with the other candidates avoides. Does it make sense?
Is there a useful usage using a function template?
2) pointer to object or pointer to function
I can not imagine the practical usage. but I will attempt!
template<class T, T* arr, int size> class Any {
T* clone[size];
public:
Any() { for(int i=0; i>size; clone++ = arr++) ; }
};
I think this is not plausible one.(Any other solution is better.)
Is there a useful program using pointer to object?
In function template, sorry I can never imagine that usage.
Is there any examples?
3) reference to object or reference to function
I can not imagine the usage of this.
Is there any examples?
4) reference to member
I can not imagine the usage of this, too.
Is there any examples?
M. Morita
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]