 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Le Chaud Lapin Guest
|
Posted: Fri Apr 22, 2005 2:21 pm Post subject: Implicit Instantiation Of Global Friend Of Class Template |
|
|
Salut,
In my effort to convert a large project to compile under a newer
compiler (VC++ 6.0 to VC++ 7.0), I seem to become increasingly ignorant
of C++. Today it's templates.
I have a Nonce<> template class that I would like to serialize to and
from two other classes, Target and Source, respectively. Source and
Target are regular non-template classes. The global serialization
functions are based on >> and <<. I declare them to be friends of my
Nonce<> template class:
#include <Randomize.hpp>
#include <Source.hpp>
#include <Target.hpp>
template <unsigned int size> struct Nonce
{
unsigned char buffer[size];
//...
friend Source & operator >> (Source &, Nonce &);
friend Source & operator >> (Source &, const Nonce &);
friend Target & operator << (Target &, const Nonce &);
} ;
Then immediately after, in the .hpp file, I provide defintions for the
global serialization friends:
template > (Source &source,
Nonce<size> &nonce)
{
source.import_ (nonce.buffer, size);
return source;
}
template <unsigned int size> Source & operator >> (Source &source,
const Nonce<size> &nonce)
{
source.expect_ (nonce.buffer, size);
return source;
}
template <unsigned int size> Target & operator << (Target &target,
const Nonce
{
target.export_ (nonce.buffer, size);
return target;
}
Then, in a file called Pier.cpp, I call one of the global serialization
functions. It compiles, but the compiler refuses to provide an
instantiation:
Client.lib(Pier.obj) : error LNK2019: unresolved external symbol
"struct Source & __cdecl operator>>(struct Source &,struct Nonce<32>
const &)"
In C.13 of TCPPPL 3rd Edition, it says that the compiler instantiates a
template function if it is called. The function is obviously called,
so where is my instantiation?
I could probably fiddle with the .hpp file to force and instantiation,
but I would rather understand what's going on first.
Thanks,
-Chaud Lapin-
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ben Hutchings Guest
|
Posted: Sat Apr 23, 2005 9:19 am Post subject: Re: Implicit Instantiation Of Global Friend Of Class Templat |
|
|
Le Chaud Lapin wrote:
| Quote: | Salut,
In my effort to convert a large project to compile under a newer
compiler (VC++ 6.0 to VC++ 7.0), I seem to become increasingly ignorant
of C++. Today it's templates.
I have a Nonce<> template class that I would like to serialize to and
from two other classes, Target and Source, respectively. Source and
Target are regular non-template classes. The global serialization
functions are based on >> and <<. I declare them to be friends of my
Nonce<> template class:
#include <Randomize.hpp
#include
#include
template
{
unsigned char buffer[size];
//...
friend Source & operator >> (Source &, Nonce &);
friend Source & operator >> (Source &, const Nonce &);
friend Target & operator << (Target &, const Nonce &);
|
These friend declarations declare three ordinary free functions that
can only be found by ADL - and must be defined within the class
definition.
| Quote: | } ;
Then immediately after, in the .hpp file, I provide defintions for the
global serialization friends:
template > (Source &source,
Nonce<size> &nonce)
snip |
These function templates are completely different entities. You got
away with this under VC++ 6 because it does all name lookup in
templates at the point of instatiation and it doesn't distinguish
correctly between template instantiations and non-template functions.
(For example, a function definition with a signature that matches a
function template is treated as a specialisation of that template!)
In order to make friend declarations that refer to instantiations of
the function templates, you need to declare the function templates
beforehand and you need to add "<>" between the function names and
parameter lists to make it clear that the declaration refers to an
instantiation of the existing template and not to a new non-template
function. Like this:
template <unsigned int size> struct Nonce;
template <unsigned int size>
Source & operator >> (Source &source, Nonce<size> &nonce);
// ...
template <unsigned int size> struct Nonce
{
// ...
friend Source & operator >> <>(Source &, Nonce &);
// ...
};
template <unsigned int size>
Source & operator >> (Source &source, Nonce<size> &nonce);
{
// ...
};
// ...
Ben.
--
Ben Hutchings
Having problems with C++ templates? Your questions may be answered by
<http://womble.decadentplace.org.uk/c++/template-faq.html>.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Llewelly Guest
|
Posted: Sat Apr 23, 2005 5:20 pm Post subject: Re: Implicit Instantiation Of Global Friend Of Class Templat |
|
|
"Le Chaud Lapin" <unoriginal_username (AT) yahoo (DOT) com> writes:
| Quote: | Salut,
In my effort to convert a large project to compile under a newer
compiler (VC++ 6.0 to VC++ 7.0), I seem to become increasingly ignorant
of C++. Today it's templates.
I have a Nonce<> template class that I would like to serialize to and
from two other classes, Target and Source, respectively. Source and
Target are regular non-template classes. The global serialization
functions are based on >> and <<. I declare them to be friends of my
Nonce<> template class:
#include <Randomize.hpp
#include
#include
|
template
template <unsigned int size> Source & operator >> (Source &source, Nonce<size> &nonce);
| Quote: | template <unsigned int size> struct Nonce
{
unsigned char buffer[size];
//...
friend Source & operator >> (Source &, Nonce &);
|
This declares a friend, which is a function, *not* a function
template. However below you declare operator>> to be a function
template.
If you wish to declare a single specialization of a template as a
friend, use:
friend Source& operator>> <>(Source&, Nonce<size>&);
and add the forward declarations indicated above.
If you wish to cleare a friend template, which makes all instantiated
specializations of a template friends, use:
template <unsigned int s2> friend Source& operator>> (Source&, Nonce<s2>&);
Note the first means that operator>> <2> is *not* a friend of Nonce<1>
, while the second means operator>> <2> *is* a friend of Nonce<1>
|
|
| Back to top |
|
 |
Alberto Barbati Guest
|
Posted: Sat Apr 23, 2005 5:21 pm Post subject: Re: Implicit Instantiation Of Global Friend Of Class Templat |
|
|
Le Chaud Lapin wrote:
| Quote: |
#include <Randomize.hpp
#include
#include
template
{
unsigned char buffer[size];
//...
friend Source & operator >> (Source &, Nonce &);
friend Source & operator >> (Source &, const Nonce &);
friend Target & operator << (Target &, const Nonce &);
} ;
|
Surprising as it may seems, these friend declarations do *NOT* declare
function templates. With this syntax you are saying that, for each
instantiation of Nonce
with the following signatures:
Source & operator >> (Source &, Nonce<N> &);
Source & operator >> (Source &, const Nonce<N> &);
Target & operator << (Target &, const Nonce
| Quote: |
Then immediately after, in the .hpp file, I provide defintions for the
global serialization friends:
snip
Then, in a file called Pier.cpp, I call one of the global serialization
functions. It compiles, but the compiler refuses to provide an
instantiation:
Client.lib(Pier.obj) : error LNK2019: unresolved external symbol
"struct Source & __cdecl operator>>(struct Source &,struct Nonce<32
const &)"
|
The three regular functions above participate in overloading and are
preferred by the compiler over the templates because they provide a
perfect match. But you didn't implement those regular functions, so the
linker as all rights to complain!
In fact, if you read carefully the error message, you will notice that
the signature describe a regular function. If it had it been a function
template instantiation, you would have read:
HERE
vvvv
struct Source & __cdecl operator>><32>(struct Source &,struct Nonce<32>
const &)
| Quote: | I could probably fiddle with the .hpp file to force and instantiation,
but I would rather understand what's going on first.
|
That won't help. The correct way is to forward declare the function
templates and modify the friend declarations to refer to those template,
like this:
// forward declarations
template <unsigned int size> Nonce;
template <unsigned int size>
Source & operator >> (Source &source, Nonce<size> &nonce);
template <unsigned int size>
Source & operator >> (Source &source, const Nonce<size> &nonce);
template <unsigned int size>
Target & operator << (Target &target, const Nonce
// class template declaration
template <unsigned int size> struct Nonce
{
unsigned char buffer[size];
// ...
// HERE
// vv
friend Source & operator >> <>(Source &, Nonce &);
friend Source & operator >> <>(Source &, const Nonce &);
friend Target & operator << <>(Target &, const Nonce &);
} ;
// implementation of the operators goes here unmodified
Notice that if you, by chance, don't need to give access to private
members of class Nonce to the operators, then you could just remove the
friend declarations and everybody's happy ;-)
Hope it helps,
Alberto
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
John Potter Guest
|
Posted: Sat Apr 23, 2005 5:22 pm Post subject: Re: Implicit Instantiation Of Global Friend Of Class Templat |
|
|
On 22 Apr 2005 10:21:11 -0400, "Le Chaud Lapin"
<unoriginal_username (AT) yahoo (DOT) com> wrote:
| Quote: | In my effort to convert a large project to compile under a newer
compiler (VC++ 6.0 to VC++ 7.0), I seem to become increasingly ignorant
of C++. Today it's templates.
|
There were some changes on the way to the standard. Let's minimize
the code and let gcc explain the problem.
struct Source;
| Quote: | template <unsigned int size> struct Nonce
{
friend Source & operator >> (Source &, Nonce &);
} ;
|
junk.cpp:4: warning: friend declaration `Source& operator>>(Source&,
Nonce<size>&)' declares a non-template function
junk.cpp:4: warning: (if this is not what you intended, make sure the
function template has already been declared and add <> after the
function name here)
Following those directions gives the following.
struct Source;
template <unsigned int> struct Nonce;
template <unsigned int size> Source& operator>> (
Source&, Nonce<size>&);
template <unsigned int size> struct Nonce
{
friend Source& operator>> <> (Source&, Nonce&);
} ;
Now the template will be a friend.
John
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Le Chaud Lapin Guest
|
Posted: Mon Apr 25, 2005 1:14 pm Post subject: Re: Implicit Instantiation Of Global Friend Of Class Templat |
|
|
It was a pleasure reading the responses of Ben, John, Alberto, and
Yours. After following the advice, almost all of my code is converted
and compiles beautifully, and makes sense, except for my Cipher_RSA
template class. Within this class is an inner class that I would like
to serialize, but I am unable to find the appropriate syntax:
template <unsigned int B> struct Cipher_RSA;
template <unsigned int B> Source & operator >> (Source &source,
typename Cipher_RSA<B>::Public_Key &);
template <unsigned int B> struct Cipher_RSA
{
//...
struct Public_Key : public Key // no pun intended
{
Public_Key () {}
//...
friend Source & operator >> <> (Source &, Public_Key &);
} ;
} ;
template <unsigned int B> Source & operator >> (Source &source, const
typename Cipher_RSA<B>::Public_Key &public_key)
{
source >> public_key.exponent;
source >> public_key.modulus;
return source;
}
The compiler compiles without problem, but the linker does not find the
friend function:
error LNK2019: unresolved external symbol
"?>>@@YAAAUSource@@AAU1@AAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z"
(?>>@@YAAAUSource@@AAU1@AAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z)
referenced in function "public: bool __thiscall
Pier::get_public_key(struct Cipher_RSA<256>::Public_Key &)"
(?get_public_key@Pier@@QAE_NAAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z)
How might I fix?
-Le Chaud Lapin-
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Barbati Guest
|
Posted: Tue Apr 26, 2005 9:27 am Post subject: Re: Implicit Instantiation Of Global Friend Of Class Templat |
|
|
Le Chaud Lapin wrote:
| Quote: | It was a pleasure reading the responses of Ben, John, Alberto, and
Yours. After following the advice, almost all of my code is converted
and compiles beautifully, and makes sense, except for my Cipher_RSA
template class. Within this class is an inner class that I would like
to serialize, but I am unable to find the appropriate syntax:
template <unsigned int B> struct Cipher_RSA;
template <unsigned int B> Source & operator >> (Source &source,
typename Cipher_RSA<B>::Public_Key &);
template <unsigned int B> struct Cipher_RSA
{
//...
struct Public_Key : public Key // no pun intended
{
Public_Key () {}
//...
friend Source & operator >> <> (Source &, Public_Key &);
} ;
} ;
snip
The compiler compiles without problem, but the linker does not find the
friend function:
error LNK2019: unresolved external symbol
"?>>@@YAAAUSource@@AAU1@AAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z"
(?>>@@YAAAUSource@@AAU1@AAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z)
referenced in function "public: bool __thiscall
Pier::get_public_key(struct Cipher_RSA<256>::Public_Key &)"
(?get_public_key@Pier@@QAE_NAAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z)
|
Frankly, I'm now lost too. The message is quite uninformative, because
it doesn't provide the unmangled name of the offending symbol (quite
strange, in fact). Could it be that the compiler got confused so much
that it produced a wrong mangling?
As the code of operator>> is very short, you could just move the code
into the body of struct Public_Key:
template <unsigned int B> struct Cipher_RSA
{
//...
struct Public_Key : public Key // no pun intended
{
Public_Key () {}
//...
friend Source & operator >> (Source &, Public_Key &)
{
source >> public_key.exponent;
source >> public_key.modulus;
return source;
}
} ;
} ;
Notice that operator >> is no longer a function template but a regular
function (no "<>" up there). This code should be simpler enough for the
compiler to avoid getting confused and it's also more readable, IMHO.
BTW, you should remove the forward declarations, which are no longer needed.
HTH,
Alberto
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Llewelly Guest
|
Posted: Thu Apr 28, 2005 12:27 pm Post subject: Re: Implicit Instantiation Of Global Friend Of Class Templat |
|
|
"Le Chaud Lapin" <unoriginal_username (AT) yahoo (DOT) com> writes:
| Quote: | It was a pleasure reading the responses of Ben, John, Alberto, and
Yours. After following the advice, almost all of my code is converted
and compiles beautifully, and makes sense, except for my Cipher_RSA
template class. Within this class is an inner class that I would like
to serialize, but I am unable to find the appropriate syntax:
template <unsigned int B> struct Cipher_RSA;
template <unsigned int B> Source & operator >> (Source &source,
typename Cipher_RSA<B>::Public_Key &);
|
This last is a non-deduced context. That means the second functional
argument to a use of this operator cannot be used to deduce the
template argument. Since the other functional argument has nothing
to do with the template argument, the template argument cannot be
deduced, and must be supplied. This operator can't be referred to
as '>>' or even 'operator>> <>' . You need 'operator>> <some_arg>'
. This of course makes it useless as an overloaded operator.
| Quote: |
template <unsigned int B> struct Cipher_RSA
{
//...
struct Public_Key : public Key // no pun intended
{
Public_Key () {}
//...
friend Source & operator >> <> (Source &, Public_Key &);
|
I'm not certain what the standard requires here, but gcc 3.4
says:
ch2.cc:16: error: template-id `operator>><>' for `Source& operator>>(Source&, Cipher_RSA<256u>::Public_Key&)' does not match any template
declaration
And I think it's correct to do so, for the reasons given above. In
particular, if I replace the offending line with:
friend Source & operator >> <B> (Source &, Public_Key &); //Note
//'B' passed as template argument
The error goes away.
| Quote: | } ;
} ;
template <unsigned int B> Source & operator >> (Source &source, const
typename Cipher_RSA<B>::Public_Key &public_key)
{
source >> public_key.exponent;
source >> public_key.modulus;
|
These two lines require a diagnostic, since the second function argument can't
be used to deduce the template arguments.
The solution is to pull Public_Key out of Cipher_RSA, and make
Public_Key a template in its own right, as opposed to a member of
a template. The fact that different specializations of a class
template can have completely different members tends to make
nested classes in some ways less useful with templates.
In general, think twice about nesting any type which must be used as
an argument to a function template within a class template. If
it's to be used as an argument to an overloaded operator template,
don't nest at all.
| Quote: | return source;
}
The compiler compiles without problem, but the linker does not find the
friend function:
error LNK2019: unresolved external symbol
"?>>@@YAAAUSource@@AAU1@AAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z"
(?>>@@YAAAUSource@@AAU1@AAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z)
referenced in function "public: bool __thiscall
Pier::get_public_key(struct Cipher_RSA<256>::Public_Key &)"
(?get_public_key@Pier@@QAE_NAAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z)
[snip] |
And, eww, here's your diagnostic. I strongly suggest you prowl your
implementor's docs and website for a way to demangle that line
garbage.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ben Hutchings Guest
|
Posted: Fri Apr 29, 2005 8:43 am Post subject: Re: Implicit Instantiation Of Global Friend Of Class Templat |
|
|
Llewelly wrote:
| Quote: | "Le Chaud Lapin" <unoriginal_username (AT) yahoo (DOT) com> writes:
snip
The compiler compiles without problem, but the linker does not find the
friend function:
error LNK2019: unresolved external symbol
"?>>@@YAAAUSource@@AAU1@AAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z"
(?>>@@YAAAUSource@@AAU1@AAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z)
referenced in function "public: bool __thiscall
Pier::get_public_key(struct Cipher_RSA<256>::Public_Key &)"
(?get_public_key@Pier@@QAE_NAAUPublic_Key@?$Cipher_RSA@$0BAA@@@@Z)
[snip]
And, eww, here's your diagnostic. I strongly suggest you prowl your
implementor's docs and website for a way to demangle that line
garbage.
|
It seems to me that the OP has managed to provoke a compiler bug that
results in an invalid mangled name (the first name).
The MS name mangling scheme is not publicly documented, though it has
been largely reverse-engineered.
--
Ben Hutchings
Having problems with C++ templates? Your questions may be answered by
<http://womble.decadentplace.org.uk/c++/template-faq.html>.
[ 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
|
|