 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Aaron Graham Guest
|
Posted: Tue Aug 15, 2006 8:54 pm Post subject: String literals and templates |
|
|
Consider the following function:
template <typename T>
void foo(const T& t) { // pass-by-reference
std::cout << t << std::endl;
}
If I call this function three times:
foo("a");
foo("bb");
foo("ccc");
....the compiler renders 3 different functions:
void foo<char [2]>(char const (&) [2]);
void foo<char [3]>(char const (&) [3]);
void foo<char [4]>(char const (&) [4]);
However, if I write foo to be pass-by-value, gcc takes this chance to
optimize the code in such a way that only one function is generated:
void foo<char const*>(char const*);
What is the easiest way to get the "best of both worlds" in this
situation? By that I mean how can I get the least amount of generated
code (only one function for all string literals) and the ability to
pass by reference?
Aaron
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Matthias Hofmann Guest
|
Posted: Tue Aug 15, 2006 11:12 pm Post subject: Re: String literals and templates |
|
|
"Aaron Graham" <atgraham (AT) gmail (DOT) com> schrieb im Newsbeitrag
news:1155653672.523935.87710 (AT) h48g2000cwc (DOT) googlegroups.com...
| Quote: | Consider the following function:
template <typename T
void foo(const T& t) { // pass-by-reference
std::cout << t << std::endl;
}
If I call this function three times:
foo("a");
foo("bb");
foo("ccc");
...the compiler renders 3 different functions:
void foo<char [2]>(char const (&) [2]);
void foo<char [3]>(char const (&) [3]);
void foo<char [4]>(char const (&) [4]);
However, if I write foo to be pass-by-value, gcc takes this chance to
optimize the code in such a way that only one function is generated:
void foo<char const*>(char const*);
What is the easiest way to get the "best of both worlds" in this
situation? By that I mean how can I get the least amount of generated
code (only one function for all string literals) and the ability to
pass by reference?
|
What about overloading foo() as follows?
template <typename T> void foo(const T& t);
template <typename T> void foo(const T* t);
I don't know what the standard has to say about this, but on Visual C++ 8.0
this seems to work as you might expect...
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Andrei Polushin Guest
|
Posted: Tue Aug 15, 2006 11:13 pm Post subject: Re: String literals and templates |
|
|
Aaron Graham wrote:
| Quote: | If I call this function three times:
foo("a");
foo("bb");
foo("ccc");
...the compiler renders 3 different functions:
void foo<char [2]>(char const (&) [2]);
void foo<char [3]>(char const (&) [3]);
void foo<char [4]>(char const (&) [4]);
However, if I write foo to be pass-by-value, gcc takes this chance to
optimize the code in such a way that only one function is generated:
void foo<char const*>(char const*);
What is the easiest way to get the "best of both worlds" in this
situation? By that I mean how can I get the least amount of generated
code (only one function for all string literals) and the ability to
pass by reference?
|
It seems you should write it as pass-by-value and let your compiler to
optimize it as pass-by-reference.
See <http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#181>
(DR 181: make_pair() unintended behavior) for further discussion.
--
Andrei Polushin
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Gennaro Prota Guest
|
Posted: Wed Aug 16, 2006 4:41 am Post subject: Re: String literals and templates |
|
|
On 15 Aug 2006 11:54:00 -0400, "Aaron Graham" <atgraham (AT) gmail (DOT) com>
wrote:
| Quote: | Consider the following function:
template <typename T
void foo(const T& t) { // pass-by-reference
std::cout << t << std::endl;
}
If I call this function three times:
foo("a");
foo("bb");
foo("ccc");
...the compiler renders 3 different functions:
void foo<char [2]>(char const (&) [2]);
void foo<char [3]>(char const (&) [3]);
void foo<char [4]>(char const (&) [4]);
However, if I write foo to be pass-by-value, gcc takes this chance to
optimize the code in such a way that only one function is generated:
void foo<char const*>(char const*);
What is the easiest way to get the "best of both worlds" in this
situation?
|
It depends on what "this situation" is Certainly the above is a
simplified example, not the real scenario. If you just want a
quick-and-easy way to go you can add
#include <cstddef>
template <std::size_t n>
void foo(const char (&x)[n])
{
return foo(static_cast<const char*>(x));
}
--
Gennaro Prota
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Ron Natalie Guest
|
Posted: Wed Aug 16, 2006 7:10 am Post subject: Re: String literals and templates |
|
|
Aaron Graham wrote:
| Quote: | Consider the following function:
template <typename T
void foo(const T& t) { // pass-by-reference
std::cout << t << std::endl;
}
If I call this function three times:
foo("a");
foo("bb");
foo("ccc");
...the compiler renders 3 different functions:
void foo<char [2]>(char const (&) [2]);
void foo<char [3]>(char const (&) [3]);
void foo<char [4]>(char const (&) [4]);
However, if I write foo to be pass-by-value, gcc takes this chance to
optimize the code in such a way that only one function is generated:
void foo<char const*>(char const*);
It's not an optimization actually. |
void foo(char[1]);
and
void foo(char[2]);
have the same type.
You can't pass arrays by value anyhow.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Aaron Graham Guest
|
Posted: Thu Aug 17, 2006 6:38 am Post subject: Re: String literals and templates |
|
|
Frederick Gotham wrote:
| Quote: | The first question that comes to mind is, why don't you simply have the
following?:
template<class T
void Foo(T const *);
If you only want an array to be passed, and if you want to retain its
length, then:
|
But my example implies that this is certainly not the case. I don't
just want arrays to be passed. Anything that has a defined operator<<
is allowed. That includes ints and std::strings as well as char arrays
and even user defined serializable objects.
Aaron
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Jeff Koftinoff Guest
|
Posted: Thu Aug 17, 2006 8:59 am Post subject: Re: String literals and templates |
|
|
Michiel.Salters (AT) tomtom (DOT) com wrote:
| Quote: | Aaron Graham wrote:
...the compiler renders 3 different functions:
void foo<char [2]>(char const (&) [2]);
void foo<char [3]>(char const (&) [3]);
void foo<char [4]>(char const (&) [4]);
So? Any decent linker will notice the functions are identical and the
addresses
aren't needed. The functions can be folded, and there should be no size
or
runtime penalty.
HTH,
Michiel.
|
Do you or does anyone know of any specific linkers which are 'decent'
and do a template-function-uniqueness check and discard identical
functions?
--jeffk++
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
James Hopkin Guest
|
Posted: Thu Aug 17, 2006 7:32 pm Post subject: Re: String literals and templates |
|
|
Matthias Hofmann wrote:
| Quote: | "James Hopkin" <tasjaevan (AT) gmail (DOT) com> schrieb im Newsbeitrag
template <typename T, typename U, typename V
void foo(const T& t, const U& u, const V& v)
{
foo_impl(
static_cast<typename Param<T>::type>(t),
static_cast<typename Param<U>::type>(u),
static_cast<typename Param<V>::type>(v) );
}
Note that if any of foo's parameters need to be non-const-qualified
references (i.e. so that const-ness is deduced from the parameter
coming in), a little more work is needed.
Am I right in thinking that a static_cast may cause a temporary to be
constructed? What about the following alternative definition of struct
Param<> to prevent this:
template <typename T
struct Param { typedef const T& type; };
|
Yes, I think you're right. My bad.
I think your idea leads to a better solution:
#include <cstddef> // for size_t
template <typename T>
const T& adapter(const T& ref) { return ref; }
template <typename T, std::size_t N>
const T* adapter(T (&array)[N]) { return array; }
template <typename T, typename U, typename V>
void foo_impl(const T& t, const U& u, const V& v)
{
}
template <typename T, typename U, typename V>
void foo(const T& t, const U& u, const V& v)
{
foo_impl(adapter(t), adapter(u), adapter(v));
}
James
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Ron Natalie Guest
|
Posted: Thu Aug 17, 2006 8:21 pm Post subject: Re: String literals and templates |
|
|
{ please refrain from using all-caps for emphasis, there are other, less
offensive ways to _underline_ or /italicize/ what you're writing. -mod }
Matthias Hofmann wrote:
| Quote: | But the arrays have different sizes, don't they? If I code as follows:
|
Yes, but YOU CAN NOT PASS ARRAYS BY VALUE TO FUNCTIONS.
As I said, for typing purposes, any array argument of type
array-of-T (any size) is changed to pointer-to-T for the
typing of the array.
This means, as I said:
void foo(char a[1]);
void foo(char b[2]);
void foo(char* c);
all have the same type:
void (char*)
You can "appear" to pass arrays to these functions because
there is a like defined conversion of array to pointer.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Thu Aug 17, 2006 8:21 pm Post subject: Re: String literals and templates |
|
|
Matthias Hofmann wrote:
| Quote: | "Ron Natalie" <ron (AT) spamcop (DOT) net> schrieb im Newsbeitrag
news:44e262c8$0$24186$9a6e19ea (AT) news (DOT) newshosting.com...
Aaron Graham wrote:
Consider the following function:
template <typename T
void foo(const T& t) { // pass-by-reference
std::cout << t << std::endl;
}
If I call this function three times:
foo("a");
foo("bb");
foo("ccc");
...the compiler renders 3 different functions:
void foo<char [2]>(char const (&) [2]);
void foo<char [3]>(char const (&) [3]);
void foo<char [4]>(char const (&) [4]);
However, if I write foo to be pass-by-value, gcc takes this
chance to optimize the code in such a way that only one
function is generated: void foo<char const*>(char const*);
It's not an optimization actually.
void foo(char[1]);
and
void foo(char[2]);
have the same type.
But the arrays have different sizes, don't they?
|
What arrays? There are no arrays in the above function
declarations. There is, in fact, no way to declare a function
to take an array as argument (although it can take a reference
to an array).
That's the reason behind the different behavior in the above
templates. Given:
template< typename T >
void f( T t ) { ... }
there is no way the compiler could instantiate T to be a char
const[2], because char const[2] is not a legal type for a
function parameter. So the compiler does what it thinks is the
next best thing; it instantiates a function that corresponds to
what you get if you actually wrote char const[2] as the
parameter, i.e.: "char const*".
| Quote: | If I code as follows:
template <class T
void foo( const T& t )
{
cout << sizeof t << endl;
}
int main()
{
foo( "a" );
foo( "bb" );
foo( "ccc" );
return 0;
}
the output I get is
2
3
4
The compiler does seem to create more than one function, so
that creating only one instead is an optimization, isn't it?
|
No. The reason is that
void foo( char const (&array)[2] ) ;
declares a function which has a parameter of type char const
(&)[2], where as
void foo( char const array[2] ) ;
declares a function which has a parameter of type char const*.
IMHO, the loss of information is a pessimization, not an
optimization; it certainly makes life more difficult for the
programmer. But it is one imposed by the language, for
historical reasons (dating back to the predecessor of C, B).
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Thu Aug 17, 2006 8:22 pm Post subject: Re: String literals and templates |
|
|
Aaron Graham wrote:
| Quote: | Frederick Gotham wrote:
The first question that comes to mind is, why don't you simply have the
following?:
template<class T
void Foo(T const *);
If you only want an array to be passed, and if you want to
retain its length, then:
But my example implies that this is certainly not the case. I
don't just want arrays to be passed. Anything that has a
defined operator<< is allowed. That includes ints and
std::strings as well as char arrays and even user defined
serializable objects.
|
In which case, the simplest solution is probably to just provide
a non template function for the char const* case. This is what
I do in my ostream wrappers, and it seems to work. I wasn't
bothered by the number of functions, but the template version
didn't instantiate correctly, I forget why. Adding the non
templated overload made it work, however.
If you want to support manipulators as well, you'll also have to
provide a non-template version for them. Since the manipulators
themselves are template functions, the compiler really doesn't
have enough to go on otherwise for type deduction.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Matthias Hofmann Guest
|
Posted: Thu Aug 17, 2006 11:06 pm Post subject: Re: String literals and templates |
|
|
"kanze" <kanze@gabi-soft.fr> schrieb im Newsbeitrag
news:1155824782.577778.56970 (AT) b28g2000cwb (DOT) googlegroups.com...
| Quote: | The compiler does seem to create more than one function, so
that creating only one instead is an optimization, isn't it?
No. The reason is that
void foo( char const (&array)[2] ) ;
declares a function which has a parameter of type char const
(&)[2], where as
void foo( char const array[2] ) ;
declares a function which has a parameter of type char const*.
|
But a 'const char (&array)[2]' is not the same as a 'const char array[2]',
is it? And according to my understanding, the following to functions do not
take arguments of identical types:
void foo( const char (&array)[2] );
void foo( const char (&array)[4] );
| Quote: | IMHO, the loss of information is a pessimization, not an
optimization; it certainly makes life more difficult for the
programmer. But it is one imposed by the language, for
historical reasons (dating back to the predecessor of C, B).
|
Where is there information being lost? If you look at the disassembly of the
following code on Visual C++ 8.0
template <class T>
void foo( const T& t )
{
cout << sizeof t << endl;
}
int main()
{
foo( "a" );
foo( "bb" );
foo( "ccc" );
return 0;
}
you can find three different functions generated for foo<>(). Each uses a
constant expression generated at compile time for the expression 'sizeof t'.
At least this applies to the debug build.
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
kanze Guest
|
Posted: Fri Aug 18, 2006 6:38 pm Post subject: Re: String literals and templates |
|
|
Matthias Hofmann wrote:
| Quote: | "kanze" <kanze@gabi-soft.fr> schrieb im Newsbeitrag
news:1155824782.577778.56970 (AT) b28g2000cwb (DOT) googlegroups.com...
The compiler does seem to create more than one function, so
that creating only one instead is an optimization, isn't it?
No. The reason is that
void foo( char const (&array)[2] ) ;
declares a function which has a parameter of type char const
(&)[2], where as
void foo( char const array[2] ) ;
declares a function which has a parameter of type char const*.
But a 'const char (&array)[2]' is not the same as a 'const
char array[2]', is it?
|
No.
| Quote: | And according to my understanding, the following to functions
do not take arguments of identical types:
void foo( const char (&array)[2] );
void foo( const char (&array)[4] );
|
These are different, and the type of the parameter is "reference
to array[n] of const char". The "top-most" type is reference,
not array.
The rule is buried in the middle of §8.3.5/3: "After determing
the type of each parameter, any parameter of tyep 'array of T'
or 'function returning T' is adjusted to be 'pointer to T' or
'pointer to function returning T', respectively." A type
'reference to T', even if T is an array, is not adjusted.
Similarly, something like 'int [3][5]' becomes 'int (*)[5]', a
pointer to an array[5] of int.
Note that this has some interesting consequences:
void foo( char const array[2] ) {}
void foo( char const array[4] ) {} // error, duplicate definition.
void bar( char const (&array)[2] ) {}
void bar( char const (&array)[4] ) {} // OK, different function.
and:
void foo( char const array[4] ) ;
void bar( char const (&array)[4] ) ;
char a[] = "a" ;
foo( a ) ; // OK
bar( a ) ; // illegal, type mismatch.
char b ;
foo( &b ) ; // OK!
bar( &b ) ; // illegal (obviously).
| Quote: | IMHO, the loss of information is a pessimization, not an
optimization; it certainly makes life more difficult for the
programmer. But it is one imposed by the language, for
historical reasons (dating back to the predecessor of C, B).
Where is there information being lost? If you look at the
disassembly of the
|
The dimension of the array is thrown away.
| Quote: | following code on Visual C++ 8.0
template <class T
void foo( const T& t )
{
cout << sizeof t << endl;
}
int main()
{
foo( "a" );
foo( "bb" );
foo( "ccc" );
return 0;
}
you can find three different functions generated for foo<>().
Each uses a constant expression generated at compile time for
the expression 'sizeof t'.
|
The information is lost when the top-level type is array, not
when it is reference. Drop the reference, and you'll get only
one function (which will output the size of a char*).
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Matthias Hofmann Guest
|
Posted: Sat Aug 19, 2006 7:27 pm Post subject: Re: String literals and templates |
|
|
"kanze" <kanze@gabi-soft.fr> schrieb im Newsbeitrag
news:1155906600.139895.74040 (AT) m79g2000cwm (DOT) googlegroups.com...
| Quote: | Where is there information being lost? If you look at the
disassembly of the
The dimension of the array is thrown away.
following code on Visual C++ 8.0
template <class T
void foo( const T& t )
{
cout << sizeof t << endl;
}
int main()
{
foo( "a" );
foo( "bb" );
foo( "ccc" );
return 0;
}
you can find three different functions generated for foo<>().
Each uses a constant expression generated at compile time for
the expression 'sizeof t'.
The information is lost when the top-level type is array, not
when it is reference. Drop the reference, and you'll get only
one function (which will output the size of a char*).
|
This is what I meant. The compiler generates only one function when passing
by value, and one for each size of the array when passing by reference.
Therefore, passing by value instead of by reference can be regarded as an
optoimization done by the programmer.
--
Matthias Hofmann
Anvil-Soft, CEO
http://www.anvil-soft.com - The Creators of Toilet Tycoon
http://www.anvil-soft.de - Die Macher des Klomanagers
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|