Topic: Specializing templates for [const] char* pointers and string
Author: Nathan Sidwell <nathan@acm.org>
Date: Fri, 30 Mar 2001 19:57:52 GMT Raw View
Scott Meyers wrote:
> Based on the results of several compilers on the original test program,
> most compiler implementers fail to see it your way. As Mumit Khan posted,
> here are the current relevant results. Recall that pc is of type const
> char* and "A" means the call is flagged as ambiguous.
>
> // VC BCC MWCW g++ Comeau WS5 WS6u1 g++-3
> // --- ----- ---- --- ------ ---- ----- -----
> f(x, pc); // S1 S1 A A S1 S1 S1 S1
> f(x, "abc"); // A S2 A A A A S1 S1
>
> Interestingly, g++ 2.95.2 yields A while g++ 2.97 yields S1. If this
> reflects a conscious decision on the part of the g++ developers, that
I'm sorry that I missed the beginning of this thread, however, this
change between 2.95 and gcc 3.0 is intentional and is in response to
defect report 214 (gcc bug 1617) which fails to talk about reference
bound template types. I implemented that code in order to resolve
something like
template <T> void foo (T const &); // G
template <T> void foo (T *); // S
foo ((int *)0);
That was reported as ambiguous, but it looks like S is more specialized
that G. From what I see of this thread, the same thing is happening in
comparing
T const & with T = const char *
against
const char *
The patches are
2001-02-12 Nathan Sidwell <nathan@codesourcery.com>
2001-01-22 Nathan Sidwell <nathan@codesourcery.com>
and should be in the gcc mail archives of around that date. Martin Sebor
was kind enough to run some tests though a set of compilers for me.
nathan
--
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
Never hand someone a gun unless you are sure where they will point it
nathan@acm.org http://www.cs.bris.ac.uk/~nathan/ nathan@cs.bris.ac.uk
---
[ 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: Alicia <awatson@texas.net>
Date: Mon, 19 Mar 2001 00:09:34 GMT Raw View
Using the GCC online compiler, I get the desired results.
Check out: http://www.codesourcery.com/gcc-compile.shtml
Here is the test program I sent it:
(Note the inline and __asm trick)
template<typename T1, typename T2>
inline void f(const T1&, const T2&) { __asm("G");}
template<typename T1> // specialized template 1 (S1)
inline void f(const T1&, const char*) { __asm("S1");}
template<typename T1> // specialized template 2 (S2)
inline void f(const T1&, char*) { __asm("S2");}
int main()
{
int x, y;
const char *pc;
char *p;
// Expected
// --------
f(x, y); // G
f(x, pc); // S1
f(x, "abc"); // S1
f(x, p); // S2
return 0;
}
I compiled -O3 to assembly and here is "main":
main:
.LFB1:
pushl %ebp
.LCFI0:
movl %esp, %ebp
.LCFI1:
#APP
G
S1
S1
S2
#NO_APP
xorl %eax, %eax
popl %ebp
ret
enjoy,
-Kenny
Scott Meyers wrote:
>
> Given two types T1 and T2, I can write a template for performing some
> function f on objects of those types:
>
> template<typename T1, typename T2>
> void f(const T1&, const T2&); // general template (G)
>
> When T2 is const char*, char*, or a string literal (const char[]), I have a
> more efficient way to perform f, so I'd like to overload f accordingly:
>
> template<typename T1> // specialized template 1 (S1)
> void f(const T1&, const char*); // for T2 == const char* or
> // T2 == a string literal
>
> template<typename T1> // specialized template 2 (S2)
> void f(const T1&, char*); // for T2 == char*
>
> Given these templates, I expect the following calls to behave like this:
>
> int x, y;
> const char *pc;
> char *p;
> // Expected
> // --------
> f(x, y); // G
> f(x, pc); // S1
> f(x, "abc"); // S1
> f(x, p); // S2
>
---
[ 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: "James Kuyper Jr." <kuyper@wizard.net>
Date: Mon, 19 Mar 2001 02:42:56 GMT Raw View
Scott Meyers wrote:
...
> Can you please be more explicit about what you're doing here? Here's G:
>
> template<typename T1, typename T2>
> void f(const T1&, const T2&); // G
>
> What is the transformed G? Does it look like this?
>
> void f(const __T1&, const __T2&); // transformed G?
>
> If so, what does it mean to "perform argument deduction against S1"? How
> can we do argument deduction from a function declaration?
I think I understand what is intended by the rules, but I think that
talking about transformations of the function templates is a confusing
way to describe the rules. The way I've found to think about it, is to
consider each template as defining a differently named function, and
checking whether either function template could be used as a wrapper for
the other:
// f2 wraps f1
template<typename T1, typename T2>
void f1(const T1&, const T2&); // G
template<typename T1> // S1
void f2(const T1&t, const char* p)
{ f1(t,p);}
==================================================
// f1 wraps f2
template<typename T1> // S1
void f2(const T1&t, const char* p);
template<typename T1, typename T2>
void f1(const T1&t1, const T2&t2) // G
{ f2(t1, t2); }
If, ignoring the return types, one function template can wrap another
for arbitrary template arguments, and the deduced template parameters
for the wrapped function call are always an exact match, then the
wrapped template is at least as specialized as the wrapping template. As
far as I can tell, this approach matches the examples given in the
standard.
---
[ 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: "James Kuyper Jr." <kuyper@wizard.net>
Date: Thu, 22 Mar 2001 21:45:32 GMT Raw View
Scott Meyers wrote:
>
> On Mon, 19 Mar 2001 02:42:56 GMT, James Kuyper Jr. wrote:
> > // f2 wraps f1
> > template<typename T1, typename T2>
> > void f1(const T1&, const T2&); // G
> >
> > template<typename T1> // S1
> > void f2(const T1&t, const char* p)
> > { f1(t,p);}
According to Andrea Ferro, this is prohibited because it involves
"trying to match "const char*" as an r-value" to an lvalue. However,
that's a problem only when the reference is non-const, which doesn't
apply in this case. Per 13.3.3.1.4, that binding counts as an identity
conversion, and thus as an exact match.
> > ==================================================
> > // f1 wraps f2
> > template<typename T1> // S1
> > void f2(const T1&t, const char* p);
> >
> > template<typename T1, typename T2>
> > void f1(const T1&t1, const T2&t2) // G
> > { f2(t1, t2); }
> >
> >
> > If, ignoring the return types, one function template can wrap another
> > for arbitrary template arguments, and the deduced template parameters
> > for the wrapped function call are always an exact match, then the
> > wrapped template is at least as specialized as the wrapping template.
>
> If I understand you, you believe that S1 can successfully wrap G, but G
> can't successfully wrap S1, so S1 is more specialized than G. You also
> believe that this call
>
> int i;
> const char *pcc;
>
> f(i, pcc);
>
> should cause S1 to be instantiated without ambiguity. Is that a correct
> summary of your beliefs?
Yes.
---
[ 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: gt5163b@prism.gatech.edu (Brian McNamara!)
Date: Fri, 16 Mar 2001 18:11:02 GMT Raw View
"James Kuyper Jr." <kuyper@wizard.net> once said:
>That's not the problem. The problem is that the standard doesn't allow
>for partial specialization of template functions. A function (templated
>or not) can overload the original, or it can be a fully specialized
>version of it, there's no other options. It's possible to achieve much
>the same effect with overloading template function as could be achieved
>if partial specialization were allowed, which is probably why it isn't.
>However, in this case it does make a difference.
I think maybe the "moral" here is "don't use function templates to do
work". The only purpose in life for a function template should be to
deduce argument types and then forward the work to a class template.
Then you can partially specialize the class template to your heart's
content. (If std::swap() forwarded forwarded the work to
std::swap_helper<T>::some_static_method(), then you could specialize
std::swap_helper< Foo<T> >, for example--something which I think you
cannot do now.)
(This strategy also implies that the 'reference-ness' of the arguments
of all of the specializations will be the same (since there are no
overloads) solving the ambiguity problem which is making us ask the
question in the first place.)
--
Brian M. McNamara lorgon@acm.org : I am a parsing fool!
** Reduce - Reuse - Recycle ** : (Where's my medication? ;) )
---
[ 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: Anatoli <REMOVETHIS.anatoli@ptc.com>
Date: Thu, 15 Mar 2001 17:51:38 GMT Raw View
Scott Meyers wrote:
> template<typename T1, typename T2>
> void f(const T1&, const T2&); // G
>
> template<typename T1> // S1
> void f(const T1&, const char*);
My understanding is that "S1" is not a specialization
of "G", but a different function template altogether.
"G" requires two const references, and specializations
of "G" can only vary types of these references.
template<typename T1>
void f(const T1&, const char* const&); // S1'
is a specialization of "G", at least according to g++.
Another specialization is
template<typename T1>
void f(const T1&, char* const&); // S2'
These two give the desired result with g++. Sorry I
don't have access to other modern compilers at
the moment;
--
Regards
Anatoli (anatoli at ptc dot com) -- opinions aren't
---
[ 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: "James Kuyper Jr." <kuyper@wizard.net>
Date: Fri, 16 Mar 2001 01:25:52 GMT Raw View
Scott Meyers wrote:
>
> On Thu, 15 Mar 2001 17:51:38 GMT, Anatoli wrote:
> > My understanding is that "S1" is not a specialization
> > of "G", but a different function template altogether.
> > "G" requires two const references, and specializations
> > of "G" can only vary types of these references.
>
> Ah. Where in the standard is this specified, i.e., that if the general
> template takes a const T&, all specializations must take a const U& where U is
> more specialized than T?
That's not the problem. The problem is that the standard doesn't allow
for partial specialization of template functions. A function (templated
or not) can overload the original, or it can be a fully specialized
version of it, there's no other options. It's possible to achieve much
the same effect with overloading template function as could be achieved
if partial specialization were allowed, which is probably why it isn't.
However, in this case it does make a difference.
---
[ 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 ]