Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Linker errors involving template

46 views
Skip to first unread message

DSF

unread,
Jan 31, 2015, 2:34:37 PM1/31/15
to
Hello!

I know I'm not giving much information here, but posting all of the
code is impractical. I am hoping someone knows the general conditions
that might make the following happen.

I have a class called "CopyDirectory". Within it is a template
container "FAList" that holds a list of the class "HashIndex".

CopyDirectory.h:

class HashIndex
{...};

class CopyDirectory
{
yadda, yadda, yadda,

FAList<HashIndex> hindex;
};

FAList has 30+ functions. CopyDirectory uses about seven of them.

When compiling the entire project, I get the following linker
errors:

Error: Error: Unresolved external 'FAList<HashIndex>::Find(const
HashIndex&) const' referenced from module copydirectory.cpp

Error: Error: Unresolved external 'FAList<HashIndex>::Add(const
HashIndex&)' referenced from module copydirectory.cpp

Error: Error: Unresolved external 'FAList<HashIndex>::XlateCI()'
referenced from module copydirectory.cpp

Error: Error: Unresolved external 'FAList<HashIndex>::GetItem(int)'
referenced from module copydirectory.cpp


Note that GetItem is not called by CopyDirectory and XlateCI is a
private function of the template. As noted, CopyDirectory uses more
of the template's functions than Add and Find. The map file shows the
other template functions used by HashIndex but, as expected, does not
show Add or Find.

This project used to compile with no errors. The only change I made
is removing "virtual" from two of the template functions (the dtor and
Sort) when I read that virtuals in a template are a "no-no." (Putting
them back to virtual made no difference.)

I know this is not much to go on, but I'm hoping it's the result of
a commonly known error or that someone can offer tests to find out
what is wrong.

Thanks,
DSF
"'Later' is the beginning of what's not to be."
D.S. Fiscus

Geoff

unread,
Jan 31, 2015, 3:07:40 PM1/31/15
to
On Sat, 31 Jan 2015 14:34:18 -0500, DSF <nota...@address.here>
wrote:

> This project used to compile with no errors. The only change I made
>is removing "virtual" from two of the template functions (the dtor and
>Sort) when I read that virtuals in a template are a "no-no." (Putting
>them back to virtual made no difference.)
>

If undoing the changes makes no difference it means you didn't
"recompile the entire project", which means you didn't clean
everything before the recompilation and re-link.

Ian Collins

unread,
Jan 31, 2015, 3:51:11 PM1/31/15
to
DSF wrote:
> Hello!
>
> I know I'm not giving much information here, but posting all of the
> code is impractical. I am hoping someone knows the general conditions
> that might make the following happen.
>
> I have a class called "CopyDirectory". Within it is a template
> container "FAList" that holds a list of the class "HashIndex".
>
> CopyDirectory.h:
>
> class HashIndex
> {...};
>
> class CopyDirectory
> {
> yadda, yadda, yadda,
>
> FAList<HashIndex> hindex;
> };
>
> FAList has 30+ functions. CopyDirectory uses about seven of them.
>
> When compiling the entire project, I get the following linker
> errors:
>
> Error: Error: Unresolved external 'FAList<HashIndex>::Find(const
> HashIndex&) const' referenced from module copydirectory.cpp

Are the member functions of FAList defined inline, or in a separate
file? If the latter, the file will probably have to be included in each
compilation unit that uses FAList.

--
Ian Collins

Chris Vine

unread,
Jan 31, 2015, 5:15:12 PM1/31/15
to
On Sat, 31 Jan 2015 14:34:18 -0500
DSF <nota...@address.here> wrote:
[snip]
> This project used to compile with no errors. The only change I made
> is removing "virtual" from two of the template functions (the dtor and
> Sort) when I read that virtuals in a template are a "no-no." (Putting
> them back to virtual made no difference.)

I have no idea what is wrong with the way you have organised the rest of
your code (probably your build scripts do not properly recompile
files which include altered files), but you seem to have misunderstood
this last point, because a destructor cannot be a function template to
begin with. There is nothing wrong with a template class having a
virtual function, including a virtual destructor. What you cannot have
is a function template in a class (templated or untemplated) which is
virtual. You seem to misunderstand the difference between a
non-static function of a template class, which can be virtual, and a
function template, which cannot.

Chris

DSF

unread,
Jan 31, 2015, 8:29:51 PM1/31/15
to
On Sat, 31 Jan 2015 12:07:27 -0800, Geoff <ge...@invalid.invalid>
wrote:
I don't see where you infer that from what I said. Compiled with or
without the functions marked virtual makes no difference in the linker
errors. I'm sure I did an entire rebuild, but just to be sure, I just
did an entire rebuild both ways. Same errors either way. Besides,
since FAList is a template, it is contained entirely in a header file.
All files including it would have to be automatically recompiled
anyway.

DSF

unread,
Jan 31, 2015, 8:40:14 PM1/31/15
to
On Sun, 01 Feb 2015 09:50:58 +1300, Ian Collins <ian-...@hotmail.com>
wrote:
To answer your question, yes. I hate it when someone answers a "or"
question with yes or no. :o)

But in this case, yes is appropriate because some functions are
inline and some are not. Reading again, I have to say no to the
separate file section. It's a template so they are all in the same
header file. (They have to be.) They are just not all defined within
the template declaration. And the header file is included in any TU
that uses FAList.

Whatever I've done, I seem to have lost the "Illegal structure
operation" error from my previous post. I hope the fix to this does
not bring it back!

Geoff

unread,
Jan 31, 2015, 8:50:26 PM1/31/15
to
On Sat, 31 Jan 2015 20:29:33 -0500, DSF <nota...@address.here>
wrote:

>>> This project used to compile with no errors. The only change I made
>>>is removing "virtual" from two of the template functions

Did it or did it not "compile without errors" until you made the
change? I inferred you fixed a working project that compiles without
errors and when you compiled it you got link errors. Then, when you
undid the changes you made it continued to compile with errors. This
told me either the project didn't re-build cleanly or the undo's
weren't exactly correct. I went with bad build process but this was
probably a mistake to assume you did a proper undo.

DSF

unread,
Jan 31, 2015, 9:00:19 PM1/31/15
to
I'm trying to digest this. To start with, I never said I had a
destructor function template, but rather a destructor template
function.

I also see where my research led me astray. I went back to the page
I read and they were not talking about template member functions, but
rather member template functions.

Just to be doubly sure.

-----------------------------------------
Virtual template member functions:

template <class T> : class Foo
{
public:
Foo();
virtual ~Foo();
...
virtual int GetFoo();
};

----------------------------------------
Virtual member function template:

template <class T> : class Foo
{
...
};

class Bar
{
...
};

class FooBar
{
public:
virtual Foo<Bar> bar; // Illegal
};

Is my understanding correct?

seeplus

unread,
Jan 31, 2015, 11:50:09 PM1/31/15
to
On Sunday, February 1, 2015 at 6:34:37 AM UTC+11, DSF wrote:
> Hello!
>
> I know I'm not giving much information here, but posting all of the
> code is impractical. I am hoping someone knows the general conditions
> that might make the following happen.
>

Are you sure that you haven't changed something and forgotten?

I have just spent 2 weeks debugging a nasty error in a large program
containing a very complicated math function which I wrote 4 (four) years ago,
and I thought that I had made no changes to this function since.

Luckily I had littered it with huge comments, one of which mentioned
Cppcheck, and it has taken this long to twig to just this little buried comment.

I had forgotten that I ran Cppcheck a long time ago on this file.
This large module was messy and it threw up lotsa problems during the checks,
which I flipped through and fixed up.
The thing still compiled OK after each cleanup, everything worked and
there was no reason to double check functions, mainly because there are 100s of them :(
It was only when I recently noticed small errors in testing that this showed up.

I dug out a backup of the module from before doing that Cppcheck
run, and found the problem I had created with those fixes.

DSF

unread,
Feb 1, 2015, 1:54:34 AM2/1/15
to
On Sat, 31 Jan 2015 17:50:17 -0800, Geoff <ge...@invalid.invalid>
wrote:
My bad. I think I was trying to say that the TU compiled with no
errors even though it contained a template with virtual functions. I
thought maybe they were causing the linker errors stated in this
thread. Taking them out made no change. I don't know why I stated
putting them back made no difference. That's obvious. (It WAS 2:34
in the morning.)

This all started with the error in my post "Debugging a template.
I'm stuck!" posted on the 25th of January. I made changes to the
project. I have no recollection of what I did or what files I
changed. But the results went from the main CPP file to stop the
compile because an object was being used with FAList without the
object having an overloaded == to the compile completing with the
linker errors listed in this thread.

Sorry for the misunderstanding,

DSF

unread,
Feb 1, 2015, 2:17:43 AM2/1/15
to
On Sat, 31 Jan 2015 14:34:18 -0500, DSF <nota...@address.here>
wrote:

Hello! (Update)
>

> I have a class called "CopyDirectory". Within it is a template
>container "FAList" that holds a list of the class "HashIndex".
>
>CopyDirectory.h:
>
>class HashIndex
>{...};
>
>class CopyDirectory
>{
>yadda, yadda, yadda,
>
>FAList<HashIndex> hindex;
>};
>
> FAList has 30+ functions. CopyDirectory uses about seven of them.
>
> When compiling the entire project, I get the following linker
>errors:
>
>Error: Error: Unresolved external 'FAList<HashIndex>::Find(const
>HashIndex&) const' referenced from module copydirectory.cpp
>
>Error: Error: Unresolved external 'FAList<HashIndex>::Add(const
>HashIndex&)' referenced from module copydirectory.cpp
>
>Error: Error: Unresolved external 'FAList<HashIndex>::XlateCI()'
>referenced from module copydirectory.cpp
>
>Error: Error: Unresolved external 'FAList<HashIndex>::GetItem(int)'
>referenced from module copydirectory.cpp
>
>
> Note that GetItem is not called by CopyDirectory and XlateCI is a
>private function of the template. As noted, CopyDirectory uses more
>of the template's functions than Add and Find. The map file shows the
>other template functions used by HashIndex but, as expected, does not
>show Add or Find.

I discovered that only Add and Find are not inlined. The other
functions called by hindex are inlined and require no generation of
template code. (I'm guessing here about inlining and no template
code. Based on the fact that a template function called GetNextItem
is translated to a call to XLateCI followed by GetItem. GetNextItem
does not show up in the error list because there is no call to it, but
this explains XLateCI and GetItem being on the error list.)

The upshot of this is I learned the above by compiling
CopyDirectory.CPP to assembler and studying the code. Templates are
created in the assembly source for *every instance* of FAList *except*
for FAList<HashIndex>. It may be coincidence that FAList was also the
star of the last mysterious error (see "Debugging a template. I'm
stuck!" posted on Jan 25th), but I suspect not.

Are there any conditions where a compiler cannot create a template
instance and produces no error? (CopyDirectory.CPP compiles
error/warning free.)

Paavo Helde

unread,
Feb 1, 2015, 2:38:26 AM2/1/15
to
DSF <nota...@address.here> wrote in
news:u4irca9g06dq8284l...@4ax.com:

> I made changes to the
> project. I have no recollection of what I did or what files I
> changed. But the results went from the main CPP file to stop the
> compile [...]

Suggesting to install and use some version control software even if you
work alone. Cannot imagine living without one any more. On Windows,
subversion+TortoiseSVN is an easy to use combo for example.

Cheers
Paavo

Paavo Helde

unread,
Feb 1, 2015, 3:07:09 AM2/1/15
to
DSF <nota...@address.here> wrote in
news:tcjrcatn10vg4ub7o...@4ax.com:

> Are there any conditions where a compiler cannot create a template
> instance and produces no error? (CopyDirectory.CPP compiles
> error/warning free.)

Some stuff is generated only in a TU which contains the definition of the
first non-inlined virtual member function. If this function is not defined
anywhere, mysterious linker errors may result.

hth
Paavo

Ian Collins

unread,
Feb 1, 2015, 3:51:44 AM2/1/15
to
seeplus wrote:
>
> I have just spent 2 weeks debugging a nasty error in a large program
> containing a very complicated math function which I wrote 4 (four) years ago,
> and I thought that I had made no changes to this function since.
>
> Luckily I had littered it with huge comments, one of which mentioned
> Cppcheck, and it has taken this long to twig to just this little buried comment.
>
> I had forgotten that I ran Cppcheck a long time ago on this file.
> This large module was messy and it threw up lotsa problems during the checks,
> which I flipped through and fixed up.
> The thing still compiled OK after each cleanup, everything worked and
> there was no reason to double check functions, mainly because there are 100s of them :(
> It was only when I recently noticed small errors in testing that this showed up.
>
> I dug out a backup of the module from before doing that Cppcheck
> run, and found the problem I had created with those fixes.

Version control is a wonderful thing....

--
Ian Collins

Chris Vine

unread,
Feb 1, 2015, 5:07:37 AM2/1/15
to
On Sat, 31 Jan 2015 21:00:02 -0500
DSF <nota...@address.here> wrote:
> On Sat, 31 Jan 2015 22:14:58 +0000, Chris Vine
> <chris@cvine--nospam--.freeserve.co.uk> wrote:
>
> >On Sat, 31 Jan 2015 14:34:18 -0500
> >DSF <nota...@address.here> wrote:
[snip]
> I'm trying to digest this. To start with, I never said I had a
> destructor function template, but rather a destructor template
> function.

You said you thought there were circumstances in which you could not
have a virtual destructor, so you made it none-virtual. Since
destructors cannot be function templates, you were wrong.

> I also see where my research led me astray. I went back to the page
> I read and they were not talking about template member functions, but
> rather member template functions.
>
> Just to be doubly sure.

[snip examples]

No, your examples are not right.

class template:

template <class T>
class X {
public:
virtual void do_it(T t) {} // fine
virtual ~X(){} // fine
};

function template:

class Y {
public:
template <class T>
void do_it(T t) {} // can't be virtual
};

Class templates cannot do type deduction, whereas function templates
can. Class templates can have virtual member functions, whereas
function templates cannot be virtual. Function templates can be
free-standing functions, or (non-virtual) member functions.

Chris

Louis Krupp

unread,
Feb 1, 2015, 5:42:07 AM2/1/15
to
On Sat, 31 Jan 2015 14:34:18 -0500, DSF <nota...@address.here>
wrote:

>Hello!
>
> I know I'm not giving much information here, but posting all of the
>code is impractical. I am hoping someone knows the general conditions
>that might make the following happen.
<snip>

Part of debugging things like this involves coming up with something
that reproduces the problem and which you *can* post. It sounds
tedious, but my guess is that in the long run, it might get you a
solution faster than speculating on which construct might have done
what.

A code sample -- even if it consists of more than one file -- gives
the people who know their stuff more to work with. It gives people
like me, with less expertise and experience, a chance to have a shot
at it.

And since you probably know your code better than anyone, the process
of cutting it down to something manageable is likely to help *you*
figure it out.

Louis

Chris Vine

unread,
Feb 1, 2015, 5:58:55 AM2/1/15
to
On Sat, 31 Jan 2015 20:39:56 -0500
DSF <nota...@address.here> wrote:
[snip]
> But in this case, yes is appropriate because some functions are
> inline and some are not. Reading again, I have to say no to the
> separate file section. It's a template so they are all in the same
> header file. (They have to be.) They are just not all defined within
> the template declaration. And the header file is included in any TU
> that uses FAList.

If you have some member functions defined within the class template
definition, and some defined outside the class template definition,
check your syntax carefully. The syntax for member functions of class
templates which are defined outside the class definition can be quite
difficult to get right, and doubly so for a function template member of
a class template defined outside the class definition (if you have any
of them).

If you provide some member function definitions within the class
template definition and some outside it, they do not all have to be
within the same header file. However (with the limited exception of
the few compilers that implemented the export keyword), if they are not
all in the same header file, the definitions must still all be visible
to every translation unit which tries to instantiate the class or use
objects of the class. You cannot tuck away the member function
definitions which are provided outside the class template definition in
a ".cc" or ".cpp" file. Separate files which contain such things are
conventionally suffixed with ".tcc" or ".tpp" and to save the sanity of
the user are usually #include'd at the end of the header file. (To the
limited extent that you would usually so #include them in the header
file, you are right that they all "have to be" within the same header
file.)

Chris

Geoff

unread,
Feb 1, 2015, 1:34:01 PM2/1/15
to
Coupled with frequent commits and sensible commit messages.

DSF

unread,
Feb 1, 2015, 1:39:17 PM2/1/15
to
On Sun, 1 Feb 2015 10:07:26 +0000, Chris Vine
Well, this is embarrassing! I have only read about them, I've never
used one, so I forgot all about function templates. (A single
function that can process a variety of types, right?) I've only been
creating class templates. A lot of what you said didn't make sense to
me. Now I understand when you said " Since destructors cannot be
function templates, you were wrong." I was trying to figure out how a
destructor could be a class. It clicked with me when I read your
examples and the term "free-standing functions" in your last
paragraph.

Sorry to bother you, but thanks for reminding me!

Chris Vine

unread,
Feb 1, 2015, 3:27:06 PM2/1/15
to
On Sun, 01 Feb 2015 13:39:01 -0500
DSF <nota...@address.here> wrote:
> [Function templates are] A single
> function that can process a variety of types, right?

Yes, that's how it works. Their distinguishing feature is that type
deduction is available and they also offer perfect forwarding in
C++11/14 via collapsible (universal) rvalue references.

Not all of this works well. One of the consequences of the fact that
function templates cannot be virtual, and that perfect forwarding
has been bolted on to C++11 via function templates, is that you cannot
have perfect forwarding of arguments with virtual functions.

Chris

DSF

unread,
Feb 1, 2015, 4:55:36 PM2/1/15
to
On Sat, 31 Jan 2015 14:34:18 -0500, DSF <nota...@address.here>
wrote:

Hello!

I want to rephrase the question in the last post.

Are there any conditions in which a class can be ineligible for use
in a template? HashIndex is the only class that exhibits this
problem. *Every* other class I have used with FAList (so far) works.

Is there something (or lack of something) in HashIndex I can
investigate? I know C++ has a voluminous set of rules. I figure I'd
ask first in case there are some do's and don'ts (a link would be
fine). If not, I can post HashIndex. (I hate posting lengthy code
because it takes so long to make it readable in the newsreader. Code
editors typically have fixed-point type, whilst newsreaders typically
do not.)

The project did compile (and run) at one time, but "one time" was
before I discovered a bug in my library code and used a simpler
program to debug it, which led to another bug found, yadda, yadda,
yadda. In other words, it's been a while. So I've been correcting
much of the program to match several library changes.

Thanks again,

Jorgen Grahn

unread,
Feb 1, 2015, 5:06:22 PM2/1/15
to
On Sun, 2015-02-01, DSF wrote:
...
> Well, this is embarrassing! I have only read about them, I've never
> used one, so I forgot all about function templates. (A single
> function that can process a variety of types, right?)

I like to think of them as what the name suggests: templates for
functions, defining a bunch of similar-looking functions, where only
some aspect (often an argument type) varies.

See any decent book on C++ for details.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Ian Collins

unread,
Feb 1, 2015, 5:10:29 PM2/1/15
to
DSF wrote:
> On Sat, 31 Jan 2015 14:34:18 -0500, DSF <nota...@address.here>
> wrote:
>
> Hello!
>
> I want to rephrase the question in the last post.
>
> Are there any conditions in which a class can be ineligible for use
> in a template? HashIndex is the only class that exhibits this
> problem. *Every* other class I have used with FAList (so far) works.

None that I can think of.

<snip>

> The project did compile (and run) at one time, but "one time" was
> before I discovered a bug in my library code and used a simpler
> program to debug it, which led to another bug found, yadda, yadda,
> yadda. In other words, it's been a while. So I've been correcting
> much of the program to match several library changes.

Roll back to a "working" version and re-apply changes until it breaks.

--
Ian Collins

Chris Vine

unread,
Feb 1, 2015, 5:41:45 PM2/1/15
to
On Sun, 01 Feb 2015 16:55:19 -0500
DSF <nota...@address.here> wrote:
> On Sat, 31 Jan 2015 14:34:18 -0500, DSF <nota...@address.here>
> wrote:
>
> Hello!
>
> I want to rephrase the question in the last post.
>
> Are there any conditions in which a class can be ineligible for use
> in a template? HashIndex is the only class that exhibits this
> problem. *Every* other class I have used with FAList (so far) works.

No, but I suspect this might be connected to your having some member
function definitions outside the class template definition. You may
have made a mistake in a way which results in what you thought was a
"definition" not in fact defining, but instead specializing. Or maybe
you haven't specialized but defined a non-member function by mistake.
In either case, you could end up with a declaration without a
definition. I hope in addition that you haven't used the C++11
"extern" keyword applied to templates, which would do the same.

If the misbehaving function is not defined in the class definition, why
not move it there and see what happens, and then go from there?

Chris

Paavo Helde

unread,
Feb 1, 2015, 5:47:36 PM2/1/15
to
DSF <nota...@address.here> wrote in
news:cj7tca5ql2b1aqitm...@4ax.com:

> On Sat, 31 Jan 2015 14:34:18 -0500, DSF <nota...@address.here>
> wrote:
>
> Hello!
>
> I want to rephrase the question in the last post.
>
> Are there any conditions in which a class can be ineligible for use
> in a template?

Lots of. Each template expects certain properties from the types for
which it is instantiated. Some of the properties are checked at
instantiation time and do not lead to errors
(http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error),
other mismatches may cause problems later (though typically in compile
stage, not in linker stage).

Example (adapted from the wikipedia article):

struct Test {
typedef int bar;
};

template <typename T>
void f(typename T::foo) {}

The class Test is ineligible for use with function template f because
there is no such type Test::foo.

hth
Paavo

DSF

unread,
Feb 1, 2015, 11:04:46 PM2/1/15
to
On Sun, 01 Feb 2015 16:47:26 -0600, Paavo Helde
<myfir...@osa.pri.ee> wrote:

>DSF <nota...@address.here> wrote in
>news:cj7tca5ql2b1aqitm...@4ax.com:
>
>> On Sat, 31 Jan 2015 14:34:18 -0500, DSF <nota...@address.here>
>> wrote:
>>
>> Hello!
>>
>> I want to rephrase the question in the last post.
>>
>> Are there any conditions in which a class can be ineligible for use
>> in a template?
>
>Lots of. Each template expects certain properties from the types for
>which it is instantiated. Some of the properties are checked at
>instantiation time and do not lead to errors
>(http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error),
>other mismatches may cause problems later (though typically in compile
>stage, not in linker stage).
>hth
>Paavo

The problem *IS* in the compile stage. The only reason it is a
linker error is that the compiler does not create an instance for
FAList<HashIndex>. As I stated before, I compiled this TU to
assembler and there is an instance of assembly code for every use of
FAList<CLASS> used in the file except for the class HashIndex.

In header:

class CopyDirectory
{
...
FAList<HashIndex> hindex;
...
};

In CPP:

void CopyDirectory::DoSomething(int something)
{
...
HashIndex hi;
...
hindex.Add(hi); // add object hi to list
...
}

When linked, hindex.Add(hi) produces an "unresolved external
FAList<HashIndex>::Add(const HashIndex&)" error because the template
class code for FAList<HashIndex> is never created.

Thanks,
0 new messages