Topic: Pointers as template parameters
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Wed, 27 Mar 2002 18:22:52 GMT Raw View
"C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
news:i38o8.214$914.66319@news2-win.server.ntlworld.com...
> "Richard Smith" <richard@ex-parrot.com> wrote in message
> > It's not really a defect, more a request for an extension.
>
> I was hoping it would count as a DR since it's about a change to an
existing
> section of the standard rather than adding a new feature. If it's not a
> defect then I probably won't submit a DR.
It's perhaps worth a try, but I wouldn't be surprised if it wasn't rejected
as an extension. Nevertheless, it might draw attention to the fact that
there's room for improvement in this area.
Incidentally, another separate but related issue is that of string literals
as template arguments. This has come up on the Boost mailing list in the
last few days, and I can see arguments allowing string literals as template
arguments of type const char *. Again, these would have to be in a
namespace from external names and pointer literals (if they were to be
allowed), but I'm sure that this doesn't impose any extra challenges to name
mangling.
Then, perhaps one could have any of the following,
template <const char *> void foo() {}
const char ch;
template void foo< &ch >();
template void foo< 0 >();
template void foo< "Hello" >();
template void foo< (const char *)0x12345678 >();
template void foo< &ch + (ptrdiff_t)0x123 >();
[ Itanium C++ ABI ]
>
> That's interesting and a bit surprising. Compare that one with these...
>
> template<int I> void fooc(int (&)[I + 1 + 1]) { }
> template void fooc<4> (int (&)[6]);
> const int x = 1 + 1;
> template<int I> void foof(int (&)[I + x]) { }
> template void foof<4> (int (&)[6]);
>
> _Z4foocILi4EEvRAplplT_Li1ELi1E_i
which means
void ::fooc<4>( int (&)[ template_parameter_1 + 1 + 1 ] );
> _Z4foofILi4EEvRAplT_L_Z1xE_i
which means
void ::fooc<4>( int (&)[ template_parameter_1 + ::x ] );
I agree this seems rather odd, and I'm unsure why they've elected to do
this, but it seems a perfectly self-consistent thing to do.
--
Richard Smith
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "C.Higgins" <chuck.higgins@ntlworld.com>
Date: Wed, 27 Mar 2002 13:12:32 GMT Raw View
"Richard Smith" <richard@ex-parrot.com> wrote in message
news:1016795135.456.0.nnrp-01.3e31d362@news.demon.co.uk...
>
> I'd not thought of writing a generic auto-handle class quite like this.
> I'll have to remember this for future use.
Yes, only a slight generalization on the idea of a smart pointer, but a
useful one. I was thinking of taking the idea over to boost to see if there
is any interest.
> OK. Good example. I'm not sure I really like API's doing things like
using
> (void*)-1 as special return codes, but it clearly happens so it probably
> ought to be properly supported.
Yes I think consistency is the thing. It's not as if I'm suggesting we add
pointer literals to the language, I'm suggesting that pointer template
parameters should behave like non-pointer types, at least as far as they do
outside of template use. Templates are for generic programming after all.
> It's not really a defect, more a request for an extension.
I was hoping it would count as a DR since it's about a change to an existing
section of the standard rather than adding a new feature. If it's not a
defect then I probably won't submit a DR.
> I had been thinking of issues to do with mangling. Allowing this would
mean
> that a compiler would need to be able to mangle arbitrary expressions into
> type names. E.g., what would be the mangling of the type
>
> test< char *, &str + 0x256 >;
>
> But some (all?) mangling schemes allow this anyway. Quoting from the
> Itanium C++ ABI (which gcc has used since 3.0):
>
> ... the declarations:
>
> template<int I> void foo (int (&)[I + 1]) { }
> template void foo<2> (int (&)[3]);
>
> produce the mangled name "_Z3fooILi2EEvRAplT_Li1E_i".
>
> which approximately means
>
> void ::foo<2>( int (&)[ template_parameter_1 + 1 ] );
>
> rather than
>
> void ::foo<2>( int (&)[3] );
That's interesting and a bit surprising. Compare that one with these...
template<int I> void fooc(int (&)[I + 1 + 1]) { }
template void fooc<4> (int (&)[6]);
const int x = 1 + 1;
template<int I> void foof(int (&)[I + x]) { }
template void foof<4> (int (&)[6]);
_Z4foocILi4EEvRAplplT_Li1ELi1E_i
_Z4foofILi4EEvRAplT_L_Z1xE_i
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Mon, 18 Mar 2002 15:51:15 GMT Raw View
"C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
news:1kyk8.8531$VP6.1291141@news2-win.server.ntlworld.com...
> "Richard Smith" <richard@ex-parrot.com> wrote in message
> news:1016186686.2545.0.nnrp-01.3e31d362@news.demon.co.uk...
> >
> > extern const char *str;
> > template <class T, T t> class test { /*...*/};
> > template <> class test< char *, &str > { /* A specialisation */ };
> > test<char *, (char*)0x12345678 > z;
> >
> > How does the compiler know *at compile time* whether the address of &str
> > happens to be 0x12345678?
>
> The two types would never be equal so it doesn't need to know.
> Here's an example of an existing implementation:
>
> template <class T, T v> struct test { /*...*/ };
> char str[] = "test";
>
> int main() {
> test<int, 0> a;
> test<char*, &str> b;
> test<char*, (char*)0> d;
> test<char*, (char*)0x12345678> e;
> return 0;
> }
>
> Compiling this with Borland C++ 5.5 and looking at the names of the
> instantiations:
It's interesting to that BCC allows arbitrary pointer values
> bcc32 -v fred.cpp
> tdump -d fred.obj
>
> you see the following:
>
> @%test$ii$i0$%
> @%test$pct1$e&@str$%
> @%test$pct1$i0$%
> @%test$pct1$i305419896$%
>
> The important point to understand is that 'test<char*, &str>' and
> 'test<char*, (char*)0x12345678>' must be treated as separate cases, one is
> defined in terms of the name 'str' and the other is defined as if the
> parameter is an integral type 'i305419896'. So they could never be the
same
> type, even if 'str' did happen to end up at that address. Comparing the
1st
> and 3rd, you can see that in fact the way it handles 'test<char*,
(char*)0>'
> is similar to 'test<int, 0>'..
OK. That's fair enough.
> To me that seems the natural way to implement it. The obvious alternative
> would be to treat the null pointer as a special one-off case, which would
> mean that 'test<char*, (char*)0>' would compile but not 'test<char*,
> (char*)0x12345678>'.
>
> Which brings us to the question of whether 'test<char *,
(char*)0x12345678>'
> should be legal?
I would argue that it shouldn't be. I'm not sure I can think of any
examples where it would be useful ... but then again, I couldn't see why
(char*)0 should be legal, and I've now been persuaded that it could be
useful.
If they were legalised, you would probably want to make it legal to allow
the use of literal pointer non-type template parameters in integral constant
expressions. So for example,
template < char *v > struct is_aligned
{
enum { value = bool(v % 4) };
};
Currently this code is not legal (although compilers needn't diagnose an
error if it isn't instantiated). I would suggest that this was legalised,
and an error given only if is_aligned is instantiated with a name rather
than a literal.
And of course, if you allow both &str and (char*)0x12345678 as a template
argumnet, do you then allow (&str + 0x256)? This looks like a whole can of
worms that's bested left closed.
--
Richard Smith
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: news_comp.std.c++_expires-2002-05-01@nmhq.net (Niklas Matthies)
Date: Tue, 19 Mar 2002 19:31:14 GMT Raw View
On Mon, 18 Mar 2002 15:51:15 GMT, Richard Smith <richard@ex-parrot.com> w=
rote:
> "C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
> news:1kyk8.8531$VP6.1291141@news2-win.server.ntlworld.com...
[=B7=B7=B7]
> > Which brings us to the question of whether 'test<char *,
> > (char*)0x12345678>' should be legal?
> =20
> I would argue that it shouldn't be. I'm not sure I can think of any
> examples where it would be useful ... but then again, I couldn't see w=
hy
> (char*)0 should be legal, and I've now been persuaded that it could be
> useful.
The latter can always be replaced with something like
char _;
char * const my_null_value =3D &_;
template <> my_template<my_null_value> ...
So the usefulness of allowing (T *) 0 is more or less marginal.
Of course, neither would it hurt to allow it, IMHO.
-- Niklas Matthies
--=20
Just remember: When you go to court, you are trusting your fate to
twelve people that weren't smart enough to get out of jury duty!
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Leavings" <leavings@attbi.com>
Date: Tue, 19 Mar 2002 19:31:26 GMT Raw View
"Richard Smith" <richard@ex-parrot.com> wrote in message
news:1016449437.23684.0.nnrp-01.3e31d362@news.demon.co.uk...
> I would argue that it shouldn't be. I'm not sure I can think of any
> examples where it would be useful ... but then again, I couldn't see why
> (char*)0 should be legal, and I've now been persuaded that it could be
> useful.
>
> If they were legalised, you would probably want to make it legal to allow
> the use of literal pointer non-type template parameters in integral constant
> expressions. So for example,
>
> template < char *v > struct is_aligned
> {
> enum { value = bool(v % 4) };
> };
>
> Currently this code is not legal (although compilers needn't diagnose an
> error if it isn't instantiated). I would suggest that this was legalised,
> and an error given only if is_aligned is instantiated with a name rather
> than a literal.
>
> And of course, if you allow both &str and (char*)0x12345678 as a template
> argumnet, do you then allow (&str + 0x256)? This looks like a whole can of
> worms that's bested left closed.
But the literal zero is a special pointer case anyway. It does not have to be
0x00000000, so I think that a special case can be made for it (extending the
current special case, that is).
Then again, you could fake it anyway.
template<class T, T V> struct map_integral {
static const T value = V;
};
template<class T, T V> const T map_integral<T, V>::value;
template<class, class> struct is_same_type : map_integral<bool, false> { };
template<class T> struct is_same_type<T, T> : map_integral<bool, true> { };
void null_function() {
return;
}
template<void (* ptr)(void)> class function {
static const bool is_valid = is_same_type<function, function<&null_function>
>::value;
};
Of course, this is a lot of extra steps to do the same thing. Not to mention
the huge plethora of possible function types with or without exception
specifications. The null pointer is an interesting border case, and there is no
good reason to disallow it.
Actually, this reminds me of something else. It is illegal to typedef a
function type (or variants) with a exception specification, however, but what if
it done indirectly? I.e. is this legal?
template<class T> struct type_to_type {
typedef T type;
};
int main(int argc, char* argv[]) {
// typedef void (* pf)(void) throw(); // error
typedef type_to_type<void (*)(void) throw()>::type;
return 0;
}
This compiles on Comeau C++ 4.2.45.2c beta #5, it also preserves the exception
specification. If this *is* legal, then the regular typedef should be legal
too. Also, you should be able to partial specialize on exception specifications
also:
template<class func_t> struct throw_list {
typedef typelist_t<null_t, null_t> result;
};
template<class R, class E1> struct throw_list<R (void) throw(E1)> {
typedef TYPELIST((E1)) result;
};
template<class R, class E1, class E2> struct throw_list<R (void) throw(E1, E2)>
{
typedef TYPELIST((E1, E2)) result;
};
// etc.
Paul Mensonides
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "C.Higgins" <chuck.higgins@ntlworld.com>
Date: Wed, 20 Mar 2002 19:18:54 GMT Raw View
"Richard Smith" <richard@ex-parrot.com> wrote in message
news:1016449437.23684.0.nnrp-01.3e31d362@news.demon.co.uk...
>
> "C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
> news:1kyk8.8531$VP6.1291141@news2-win.server.ntlworld.com...
> > "Richard Smith" <richard@ex-parrot.com> wrote in message
> > news:1016186686.2545.0.nnrp-01.3e31d362@news.demon.co.uk...
> > >
> > template <class T, T t> class test { /*...*/ };
> >
> > Which brings us to the question of whether 'test<char *,
> (char*)0x12345678>'
> > should be legal?
>
> I would argue that it shouldn't be. I'm not sure I can think of any
> examples where it would be useful ... but then again, I couldn't see why
> (char*)0 should be legal, and I've now been persuaded that it could be
> useful.
Well, absolute addresses come up in systems programming, and there are APIs
which use them as error return values (wrongly perhaps). There seems to be
agreement that the null pointer at least is needed, and it would need to be
treated as a separate case from 'test<char*, &str>'. Allowing absolute
addresses in general could be a way to achieve that, though it's not the
only possibility.
If you're writing a template where the parameter is always an absolute
address, then you could use an integral type and then cast it (though it
might be a shame to do it that way in some cases). However that's not
possible if the type of the value is also a parameter (like 'class test') so
that it can be used with both pointer and non-pointer types.
So for example, a class to take ownership of some resource, releasing it on
destruction:
template <class T, class F, F del, T inv = T()>
class auto_hndl
{
/*....*/
};
where 'del' is a unary function to release the resource and 'inv' is an
'invalid' value that doesn't need releasing.
auto_hndl<int, int(*)(int), &close, -1> fd(open(...));
auto_hndl<int, void(*)(FILE*), &fclose> fp(fopen(...));
auto_hndl<char*, void(*)(void*), &free) p(malloc(...));
it seems surprising that the 1st is legal, but not the others.
I've found a real world example where the 'invalid value' is a non-null
pointer in the Windows API, where CreateFile returns a value
INVALID_HANDLE_VALUE which turns out to be defined as (void*)-1.
typedef BOOL WINAPI (*CloseHandlePtr)(HANDLE);
typedef auto_hndl<HANDLE, CloseHandlePtr,
&CloseHandle, INVALID_HANDLE_VALUE> AutoHandle;
AutoHandle h(CreateFile(...));
> If they were legalised, you would probably want to make it legal to allow
> the use of literal pointer non-type template parameters in integral
constant
> expressions. So for example,
>
> template < char *v > struct is_aligned
> {
> enum { value = bool(v % 4) };
> };
>
> Currently this code is not legal (although compilers needn't diagnose an
> error if it isn't instantiated). I would suggest that this was legalised,
> and an error given only if is_aligned is instantiated with a name rather
> than a literal.
Perhaps it would be useful in the world of systems programming to be able to
use a literal pointer converted to an integral type in integral constant
expressions. And if it were legal then I think you're right you would expect
it to work for template parameters iff they are absolute addresses. That is
actually how it is with Borland's compiler.
> And of course, if you allow both &str and (char*)0x12345678 as a template
> argumnet, do you then allow (&str + 0x256)? This looks like a whole can
of
> worms that's bested left closed.
Yes that would be another case again. I don't see any reason why it wouldn't
work, but then again I can't think of a need for it either. If literal
pointers, on the other hand, were allowed as template parameters then you
would probably expect constant expressions involving them to also be
allowed.
I was thinking of putting in a DR on this. Would that be an appropriate way
forward? I think people agree on the null pointer case, but I'm not sure
about the general literal pointer idea.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Fri, 22 Mar 2002 16:54:46 GMT Raw View
"C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
news:2X4m8.11584$OZ3.2129240@news6-win.server.ntlworld.com...
[ ... ]
> Well, absolute addresses come up in systems programming,
OK. This is not an area in which I have any experience.
> and there are APIs
> which use them as error return values (wrongly perhaps).
Thinking about it, even the C++ standard has one such function, signal,
inheritted from the C standard. The returned signal-handler may be one of
the special values SIG_IGN, SIG_DFL or SIG_ERR, which are very frequently
defined as (void (*)(int))1, (void (*)(int))0 and (void (*)(int))-1
respectively.
[ ... ]
> So for example, a class to take ownership of some resource, releasing it
on
> destruction:
>
> template <class T, class F, F del, T inv = T()>
> class auto_hndl
> {
> /*....*/
> };
>
> where 'del' is a unary function to release the resource and 'inv' is an
> 'invalid' value that doesn't need releasing.
>
> auto_hndl<int, int(*)(int), &close, -1> fd(open(...));
> auto_hndl<int, void(*)(FILE*), &fclose> fp(fopen(...));
^^^
FILE * presumably?
> auto_hndl<char*, void(*)(void*), &free) p(malloc(...));
>
> it seems surprising that the 1st is legal, but not the others.
I'd not thought of writing a generic auto-handle class quite like this.
I'll have to remember this for future use.
> I've found a real world example where the 'invalid value' is a non-null
> pointer in the Windows API, where CreateFile returns a value
> INVALID_HANDLE_VALUE which turns out to be defined as (void*)-1.
>
> typedef BOOL WINAPI (*CloseHandlePtr)(HANDLE);
> typedef auto_hndl<HANDLE, CloseHandlePtr,
> &CloseHandle, INVALID_HANDLE_VALUE> AutoHandle;
> AutoHandle h(CreateFile(...));
OK. Good example. I'm not sure I really like API's doing things like using
(void*)-1 as special return codes, but it clearly happens so it probably
ought to be properly supported.
[ ... ]
> > And of course, if you allow both &str and (char*)0x12345678 as a
template
> > argumnet, do you then allow (&str + 0x256)? This looks like a whole can
> of
> > worms that's bested left closed.
>
> Yes that would be another case again. I don't see any reason why it
wouldn't
> work,
I had been thinking of issues to do with mangling. Allowing this would mean
that a compiler would need to be able to mangle arbitrary expressions into
type names. E.g., what would be the mangling of the type
test< char *, &str + 0x256 >;
But some (all?) mangling schemes allow this anyway. Quoting from the
Itanium C++ ABI (which gcc has used since 3.0):
... the declarations:
template<int I> void foo (int (&)[I + 1]) { }
template void foo<2> (int (&)[3]);
produce the mangled name "_Z3fooILi2EEvRAplT_Li1E_i".
which approximately means
void ::foo<2>( int (&)[ template_parameter_1 + 1 ] );
rather than
void ::foo<2>( int (&)[3] );
> but then again I can't think of a need for it either. If literal
> pointers, on the other hand, were allowed as template parameters then you
> would probably expect constant expressions involving them to also be
> allowed.
Yes. I guess there aren't any technical reasons not to allow it.
> I was thinking of putting in a DR on this. Would that be an appropriate
way
> forward?
It's not really a defect, more a request for an extension. The current
rules are quite clear -- no literals are allowed, not even a null pointer
literal. What happens to DRs that get classified as an extension? Do they
eventually get considered for inclusion in a future standard? If so, I
think this would be a good idea.
> I think people agree on the null pointer case, but I'm not sure
> about the general literal pointer idea.
Your argument about non-zero 'special' return codes has done a lot to
convince me that they might be a good idea.
--
Richard Smith
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Thu, 14 Mar 2002 02:03:51 GMT Raw View
"C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
news:ccMj8.47270$yc2.5166959@news2-win.server.ntlworld.com...
> suppose:
>
> template <class T, T t> class test { /*...*/};
>
> would either of the following be legal?
>
> test<char*, 0> x;
> test<char*, (char*)0> y;
No, see 14.3.2/1:
A template-argument for a non-type, non-template template-parameter shall be
one of
- integral constant-expression of integral or enumeration
type; or
- the name of a non-type template-parameter; or
- the name of an object or function with external linkage,
including function templates and function template-ids
but excluding non-static class members, expressed as
id-expression; or
- the address of an object or function with external linkage,
including function templates and function template-ids
but excluding non-static class members, expressed as
& id-expression where the & is optional if the name refers
to a function or array; or
- a pointer to member expressed as described in 5.3.1.
So pointers, such as char *, are only legal in forth case and this only
allows the argument to be the address of a named object which 0 and (char
*)0 are not. It is probably better not to think of template parameters of
pointer type as pointers but as the names of objects. (This is usually how
they are implemented.)
--
Richard Smith
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Carl Daniel" <cpdaniel@pacbell.net>
Date: Thu, 14 Mar 2002 02:04:32 GMT Raw View
"Leavings" <leavings@attbi.com> wrote in message
news:000001c1cacf$eeb8bd10$7772e50c@c161550a...
> "C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
> news:ccMj8.47270$yc2.5166959@news2-win.server.ntlworld.com...
> > suppose:
> >
> > template <class T, T t> class test { /*...*/};
> >
> > would either of the following be legal?
> >
> > test<char*, 0> x;
> > test<char*, (char*)0> y;
>
> According to the standard, you can use 'T' in trailing arguments, and you
can
> have a pointer as a template argument. So, as long a 'T' is a valid type
to
> have as template argument, it should work fine.
>
> Comeau C++ 4.2.45.2c BETA#5 says this about the first one:
>
> error: argument of type "int" is incompatible with template parameter of
type
> "char *"
I'm not sure that either of them should work.
14.3.2 Template non-type arguments [temp.arg.nontype]
A template-argument for a non-type, non-template template-parameter shall be
one of:
- an integral constant expression of integral or enumeration type; or
- the name of a non-type template parameter; or
- the name of an object or function with external linkage, including
function templates and function template-ids but excluding non-static class
members, expressed as id-expression; or
- the address of an object or function with external linkage, including
function templates and function template-ids but excluding non-static class
members, expressed as & id-expression where the & is optional if the name
refers to a function or array; or
- a pointer to member as described in 5.3.1.
The constant 0 does match the first alternative, but the resulting parameter
is of type int and so is incompatible with the template specification.
The expression (char*)0 is of the right type, but does not fit any of the
above categories - seems to me that it should fail as well.
-cd
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "C.Higgins" <chuck.higgins@ntlworld.com>
Date: Thu, 14 Mar 2002 13:40:34 GMT Raw View
"Carl Daniel" <cpdaniel@pacbell.net> wrote in message
news:BVPj8.6269$Ep5.2340383881@newssvr21.news.prodigy.com...
> "Leavings" <leavings@attbi.com> wrote in message
> news:000001c1cacf$eeb8bd10$7772e50c@c161550a...
> > "C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
> > news:ccMj8.47270$yc2.5166959@news2-win.server.ntlworld.com...
> > > suppose:
> > >
> > > template <class T, T t> class test { /*...*/};
> > >
> > > would either of the following be legal?
> > >
> > > test<char*, 0> x;
> > > test<char*, (char*)0> y;
> >
>
> I'm not sure that either of them should work.
>
That's what I thought. An oversight do you think? Seems a bit daft for
'test<int, 0> x;' to be legal but not 'test<char*, (char*)0> y;'.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Thu, 14 Mar 2002 17:13:04 GMT Raw View
"C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
news:Pp_j8.48596$y76.5829098@news6-win.server.ntlworld.com...
> "Carl Daniel" <cpdaniel@pacbell.net> wrote in message
> news:BVPj8.6269$Ep5.2340383881@newssvr21.news.prodigy.com...
> > "Leavings" <leavings@attbi.com> wrote in message
> > news:000001c1cacf$eeb8bd10$7772e50c@c161550a...
> > > "C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
> > > news:ccMj8.47270$yc2.5166959@news2-win.server.ntlworld.com...
> > > > suppose:
> > > >
> > > > template <class T, T t> class test { /*...*/};
> > > >
> > > > would either of the following be legal?
> > > >
> > > > test<char*, 0> x;
> > > > test<char*, (char*)0> y;
> > >
> >
> > I'm not sure that either of them should work.
>
> That's what I thought. An oversight do you think?
I'm sure it's not. Pointer template parameters are not really templating on
the address in memory -- the template instantiations have to happen before
the compiler has any idea what the value of an address is -- they are
templating on the name of an object.
> Seems a bit daft for
> 'test<int, 0> x;' to be legal but not 'test<char*, (char*)0> y;'.
No. Integer non-type template parameters and pointer non-type template
parameters are *completely* different things. It is unfortunate really that
they have the same syntax. You cannot pass a variable (even one with
external linkage) as a pointer non-type template parameter, you can only
pass it the name of an object prefixed with an ampersand.
// At global scope
extern char *str;
extern char ch;
int main()
{
test< char *, str > x; // Illegal.
char *p_ch = &ch;
test< char *, p_ch > y; // Illegal.
char &r_ch = ch;
test< char *, &r_ch > w; // Illegal.
test< char *, &ch > z; // OK.
}
The name of the template instantiation generated by this code is something
like
class test< char *, &ch >;
and not, say,
class test< char *, 0x12345678 >;
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "C.Higgins" <chuck.higgins@ntlworld.com>
Date: Thu, 14 Mar 2002 22:46:56 GMT Raw View
"Richard Smith" <richard@ex-parrot.com> wrote in message
news:1016125224.28585.0.nnrp-01.3e31d362@news.demon.co.uk...
> > > > "C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
> > > > news:ccMj8.47270$yc2.5166959@news2-win.server.ntlworld.com...
> > > > > suppose:
> > > > >
> > > > > template <class T, T t> class test { /*...*/};
> > > > >
> > > > > would either of the following be legal?
> > > > >
> > > > > test<char*, 0> x;
> > > > > test<char*, (char*)0> y;
> > > >
> > >
> > > I'm not sure that either of them should work.
> >
> > That's what I thought. An oversight do you think?
>
> I'm sure it's not. Pointer template parameters are not really templating
on
> the address in memory -- the template instantiations have to happen before
> the compiler has any idea what the value of an address is -- they are
> templating on the name of an object.
>
I don't think that there's any technical reason that 'test<char*, (char*)0>
x' wouldn't work. It's implementation would be similar to 'test<int, 0> x'
rather than 'test<char*, &ch> x'. The difference between '&ch' and
'(char*)0' being that (char*)0 doesn't point to anything, it's a pattern of
bits that's known at compile time (I'm using, char* as a 'for instance' of
course, I mean any pointer).
In fact most of the compilers I've tried do implement it. Of the three
compilers I've tried, two will accept 'test<char*, (char*)0>', and Mr
Leavings kindly tried Comeau C++ which would also accept it. So that's three
out of four. The odd man out is g++.
When I came across this I at first thought that I had found a bug in g++,
but on looking at the standard I came to the conclusion that g++ was
probably doing it right and everybody else was wrong. I made a posting about
it a few days ago:
http://groups.google.com/groups?q=Chuck+comp.lang.c%2B%2B&hl=en&ie=ISO-8859-
1&oe=ISO-8859-1&scoring=d&selm=PF6g8.27066%24R16.3865455%40news11-gui.server
..ntli.net&rnum=9
Anyway my feeling is that it would be nice if g++ could change to match the
others rather than the other way around. What does everybody think?
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@attbi.com>
Date: Fri, 15 Mar 2002 07:05:25 GMT Raw View
"C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
news:a59k8.52869$y76.6489111@news6-win.server.ntlworld.com...
>
> I don't think that there's any technical reason that 'test<char*, (char*)0>
> x' wouldn't work. It's implementation would be similar to 'test<int, 0> x'
> rather than 'test<char*, &ch> x'. The difference between '&ch' and
> '(char*)0' being that (char*)0 doesn't point to anything, it's a pattern of
> bits that's known at compile time (I'm using, char* as a 'for instance' of
> course, I mean any pointer).
>
> In fact most of the compilers I've tried do implement it. Of the three
> compilers I've tried, two will accept 'test<char*, (char*)0>', and Mr
> Leavings kindly tried Comeau C++ which would also accept it. So that's three
> out of four. The odd man out is g++.
>
> Anyway my feeling is that it would be nice if g++ could change to match the
> others rather than the other way around. What does everybody think?
I definitely agree. There is no good reason to disallow it. Especially since
you can explicitly or partially specialize the template based on a null pointer.
I already use it to implement a (somewhat invasive) form of multi-methods. I
needed a way to 'use' a function pointer as a compile-time constant. So I
wrapped the function with a type, but I needed a partial specialization for a
null pointer to function.
struct null_t;
template<class func_t> struct function;
template<class R> struct function<R (void)> {
template<R (* ptr)(void), class dummy = null_t> struct pointer {
enum { is_valid = true };
};
template<class dummy> struct pointer<static_cast<R (*)(void)>(0), dummy> {
enum { is_valid = false };
};
};
// etc..
The compile-time lookup mechanism depends on the null pointer to continue a
tier-based lookup.
Paul Mensonides
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Fri, 15 Mar 2002 15:22:58 GMT Raw View
"C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
news:a59k8.52869$y76.6489111@news6-win.server.ntlworld.com...
> "Richard Smith" <richard@ex-parrot.com> wrote in message
> news:1016125224.28585.0.nnrp-01.3e31d362@news.demon.co.uk...
> > > > > "C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
> > > > > news:ccMj8.47270$yc2.5166959@news2-win.server.ntlworld.com...
> > > > > > suppose:
> > > > > >
> > > > > > template <class T, T t> class test { /*...*/};
> > > > > >
> > > > > > would either of the following be legal?
> > > > > >
> > > > > > test<char*, 0> x;
> > > > > > test<char*, (char*)0> y;
> > > > >
> > > >
> > > > I'm not sure that either of them should work.
> > >
> > > That's what I thought. An oversight do you think?
> >
> > I'm sure it's not. Pointer template parameters are not really
templating
> on
> > the address in memory -- the template instantiations have to happen
before
> > the compiler has any idea what the value of an address is -- they are
> > templating on the name of an object.
> >
>
> I don't think that there's any technical reason that 'test<char*,
(char*)0>
> x' wouldn't work. It's implementation would be similar to 'test<int, 0> x'
> rather than 'test<char*, &ch> x'. The difference between '&ch' and
> '(char*)0' being that (char*)0 doesn't point to anything, it's a pattern
of
> bits that's known at compile time (I'm using, char* as a 'for instance' of
> course, I mean any pointer).
It's not the fact that the bit-pattern is known at compile time that makes
this OK: it's the fact that (char*)0 can never be the address of an object.
The bits of (char*)0x12345678 are known at compile time, but if I have the
code
extern const char *str;
template <class T, T t> class test { /*...*/};
template <> class test< char *, &str > { /* A specialisation */ };
test<char *, (char*)0x12345678 > z;
How does the compiler know *at compile time* whether the address of &str
happens to be 0x12345678?
I agree it wouldn't impose any extra technical issues if a null pointer
constants were allowed as non-type template parameters, I'm just not
convinced that there is any need for the construct to be legal.
> In fact most of the compilers I've tried do implement it. Of the three
> compilers I've tried, two will accept 'test<char*, (char*)0>', and Mr
> Leavings kindly tried Comeau C++ which would also accept it. So that's
three
> out of four. The odd man out is g++.
It surprises me somewhat that Comeau compiles 'test<char*, (char*)0>', even
in strict mode, although you are quite correct that it does. I wonder
whether there might be some other wording in the standard to make this
legal -- it seems very unlike Comeau to accept something like this it they
believe it to be illegal.
--
Richard Smith
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Richard Smith" <richard@ex-parrot.com>
Date: Fri, 15 Mar 2002 19:29:51 GMT Raw View
"Paul Mensonides" <pmenso57@attbi.com> wrote in message
news:GDck8.40286$q2.5816@sccrnsc01...
[ null pointer constants as non-type template arguments ]
> I definitely agree. There is no good reason to disallow it. Especially
since
> you can explicitly or partially specialize the template based on a null
pointer.
Can you? Legally?
> I already use it to implement a (somewhat invasive) form of multi-methods.
I
> needed a way to 'use' a function pointer as a compile-time constant. So I
> wrapped the function with a type, but I needed a partial specialization
for a
> null pointer to function.
>
> struct null_t;
>
> template<class func_t> struct function;
>
> template<class R> struct function<R (void)> {
> template<R (* ptr)(void), class dummy = null_t> struct pointer {
> enum { is_valid = true };
> };
> template<class dummy> struct pointer<static_cast<R (*)(void)>(0),
dummy> {
> enum { is_valid = false };
> };
> };
Ah. Now I see why it could be useful.
--
Richard Smith
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "C.Higgins" <chuck.higgins@ntlworld.com>
Date: Sat, 16 Mar 2002 15:44:26 GMT Raw View
"Richard Smith" <richard@ex-parrot.com> wrote in message
news:1016186686.2545.0.nnrp-01.3e31d362@news.demon.co.uk...
> > > > > > "C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
> > > > > > news:ccMj8.47270$yc2.5166959@news2-win.server.ntlworld.com...
> > > > > > > suppose:
> > > > > > >
> > > > > > > template <class T, T t> class test { /*...*/};
> > > > > > >
> > > > > > > would either of the following be legal?
> > > > > > >
> > > > > > > test<char*, 0> x;
> > > > > > > test<char*, (char*)0> y;
>
> It's not the fact that the bit-pattern is known at compile time that makes
> this OK: it's the fact that (char*)0 can never be the address of an
object.
> The bits of (char*)0x12345678 are known at compile time, but if I have the
> code
>
> extern const char *str;
> template <class T, T t> class test { /*...*/};
> template <> class test< char *, &str > { /* A specialisation */ };
> test<char *, (char*)0x12345678 > z;
>
> How does the compiler know *at compile time* whether the address of &str
> happens to be 0x12345678?
The two types would never be equal so it doesn't need to know. Here's an
example of an existing implementation:
template <class T, T v> struct test { /*...*/ };
char str[] = "test";
int main() {
test<int, 0> a;
test<char*, &str> b;
test<char*, (char*)0> d;
test<char*, (char*)0x12345678> e;
return 0;
}
Compiling this with Borland C++ 5.5 and looking at the names of the
instantiations:
bcc32 -v fred.cpp
tdump -d fred.obj
you see the following:
@%test$ii$i0$%
@%test$pct1$e&@str$%
@%test$pct1$i0$%
@%test$pct1$i305419896$%
The important point to understand is that 'test<char*, &str>' and
'test<char*, (char*)0x12345678>' must be treated as separate cases, one is
defined in terms of the name 'str' and the other is defined as if the
parameter is an integral type 'i305419896'. So they could never be the same
type, even if 'str' did happen to end up at that address. Comparing the 1st
and 3rd, you can see that in fact the way it handles 'test<char*, (char*)0>'
is similar to 'test<int, 0>'..
To me that seems the natural way to implement it. The obvious alternative
would be to treat the null pointer as a special one-off case, which would
mean that 'test<char*, (char*)0>' would compile but not 'test<char*,
(char*)0x12345678>'.
Which brings us to the question of whether 'test<char *, (char*)0x12345678>'
should be legal?
> I agree it wouldn't impose any extra technical issues if a null pointer
> constants were allowed as non-type template parameters, I'm just not
> convinced that there is any need for the construct to be legal.
>
I see you're ok with the example from Paul Mensonides.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "C.Higgins" <chuck.higgins@ntlworld.com>
Date: Wed, 13 Mar 2002 19:04:38 GMT Raw View
suppose:
template <class T, T t> class test { /*...*/};
would either of the following be legal?
test<char*, 0> x;
test<char*, (char*)0> y;
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Leavings" <leavings@attbi.com>
Date: Wed, 13 Mar 2002 15:35:28 CST Raw View
"C.Higgins" <chuck.higgins@ntlworld.com> wrote in message
news:ccMj8.47270$yc2.5166959@news2-win.server.ntlworld.com...
> suppose:
>
> template <class T, T t> class test { /*...*/};
>
> would either of the following be legal?
>
> test<char*, 0> x;
> test<char*, (char*)0> y;
According to the standard, you can use 'T' in trailing arguments, and you can
have a pointer as a template argument. So, as long a 'T' is a valid type to
have as template argument, it should work fine.
Comeau C++ 4.2.45.2c BETA#5 says this about the first one:
error: argument of type "int" is incompatible with template parameter of type
"char *"
I don't know why it's not performing the 0->pointer conversion by itself, but
the second one compiles fine. The explicit C++-style version compiles as well:
test<char*, static_cast<char*>(0)> z;
Actually, I have two templates like this that I use for meta-programming,
primarily to alleviate having to define static constants outside of the class
all over the place.
// map_integral
template<class T, T V> struct map_integral {
static const T value = V;
};
template<class T, T V> const T map_integral<T, V>::value;
-- and --
// map_non_integral
template<class T, T V> struct map_non_integral {
static const T value;
};
template<class T, T V> const T map_non_integral<T, V>::value = V;
----------
I use these to strongly type some of the 'is_ptr'-type things from Loki and
other meta-programming libraries (to avoid the use of enumerations). E.g.
template<class T> struct is_ptr : map_integral<bool, false> { };
template<class T> struct is_ptr<T*> : map_integral<bool, true> { };
In this scenario, 'is_ptr<T>::value' actually *is* a bool not an enumeration,
that way if I need to overload with it, it will work correctly.
Does this help?
Paul Mensonides
---
[ 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://www.research.att.com/~austern/csc/faq.html ]