template class, methods and friend, unable to link


S

suresh.amritapuri

Hi,

This is my code:
//tree.h file
#ifndef TREE_H_
#define TREE_H_
#include "factorGraph.h"
template <typename Vertex>
class Tree{
public:
Tree(FactorGraph f):fg(f){}
Vertex root(){return root;} //returns the root
void root(Vertex rt){rootVertex=rt;} //sets the root
friend ostream & operator<<(ostream& o, const Tree<Vertex>& );
void test();

private:
Vertex rootVertex;
FactorGraph fg;
};
#endif /* TREE_H_ */

//tree.cpp file
#include "tree.h"
template<typename Vertex>
ostream & operator<< <>(ostream& o, const Tree<Vertex>& t ){
o << t.fg << endl;
return o;
}
template<typename Vertex>
void Tree<Vertex>::test(){ cout << "Namasivayah" << endl;}

I compile like this:
g++ -c tree.cpp -o tree.o
and link with other object files in my project.

I get the following linker errors:
undefined reference to `Tree<vertex_properties>::test()'
undefined reference to `operator<<(std::basic_ostream<char,
std::char_traits<char> >&, Tree<vertex_properties> const&)'
collect2: ld returned 1 exit status

I tried including the tree.cpp file at the end of tree.h. But even
then operator<< function is not compiling.
How do I go further?
suresh
 
Ad

Advertisements

S

suresh.amritapuri

suresh.amritapuri said:
This is my code:
//tree.h file
#ifndef TREE_H_
#define TREE_H_
#include "factorGraph.h"
template <typename Vertex>
class Tree{ [..]
};
#endif /* TREE_H_ */
//tree.cpp file
#include "tree.h"
template<typename Vertex>
ostream & operator<< <>(ostream& o, const Tree<Vertex>& t ){
[..] }
template<typename Vertex>
void Tree<Vertex>::test(){ cout << "Namasivayah" << endl;}
I compile like this:
g++ -c tree.cpp -o tree.o
and link with other object files in my project.
I get the following linker errors:
undefined reference to `Tree<vertex_properties>::test()'
undefined reference to `operator<<(std::basic_ostream<char,
std::char_traits<char> >&, Tree<vertex_properties> const&)'
collect2: ld returned 1 exit status
I tried including the tree.cpp file at the end of tree.h. But even
then operator<< function is not compiling.
How do I go further?

Read the FAQ section 35.  Especially the "linker error" questions there..

It is always a good idea to read the FAQ before posting.  You can find
the FAQ here:http://www.parashift.com/c++-faq-lite/

V

Hi,

Thanks, but reading the faq did not help me :( Here is my modification
and still g++ cribs. has indicated error against the two offending
lines
Any suggestions pls?
suresh

//tree.h
#include "factorGraph.h"
template <typename Vertex>
class Tree{
public:
Tree(FactorGraph f):fg(f){}
//Vertex root(){return root;} //returns the root
void root(Vertex rt){rootVertex=rt;} //sets the root
friend ostream & operator<< (ostream& o, const Tree<Vertex>& );
void test();

private:
Vertex rootVertex;
FactorGraph fg;
};
//#include "tree.cpp"
#endif /* TREE_H_ */

//tree.cpp
#include "tree.h"
template<typename Vertex> class Tree;
template<typename Vertex> ostream & operator<<(ostream& o, const
Tree<Vertex>& t );
template<typename Vertex> void Tree<Vertex>::test(void); //error:
declaration of ‘void Tree<Vertex>::test()’ outside of class is not
definition

template<typename Vertex>
ostream & operator<<(ostream& o, const Tree<Vertex>& t ){
//o << t.fg << endl;
return o;
}

template<typename Vertex>
void Tree<Vertex>::test(){ cout << "Namasivayah" << endl;}

template class Tree<Vertex>;

template ostream& operator<<<Vertex>(ostream& o, const Tree<Vertex>&
t );
template void Tree<Vertex>::test<Vertex>();//error: variable or field
‘test’ declared void, expected `;' before ‘<’ token
 
V

Victor Bazarov

suresh.amritapuri said:
> [..]
Thanks, but reading the faq did not help me :(

Mmm... Didn't it? You don't have linker errors any longer, do you?
> Here is my modification
and still g++ cribs. has indicated error against the two offending
lines
Any suggestions pls?
suresh

//tree.h
#include "factorGraph.h"
template <typename Vertex>
class Tree{
public:
Tree(FactorGraph f):fg(f){}
//Vertex root(){return root;} //returns the root
void root(Vertex rt){rootVertex=rt;} //sets the root
friend ostream & operator<< (ostream& o, const Tree<Vertex>& );
void test();

private:
Vertex rootVertex;
FactorGraph fg;
};
//#include "tree.cpp"
#endif /* TREE_H_ */

//tree.cpp
#include "tree.h"
template<typename Vertex> class Tree;

Uh... Why do you need this [re-]declaration? Doesn't the header contain
the definition of the 'Tree' class template?
template<typename Vertex> ostream & operator<<(ostream& o, const
Tree<Vertex>& t );

OK, a declaration.
template<typename Vertex> void Tree<Vertex>::test(void); //error:
declaration of ‘void Tree<Vertex>::test()’ outside of class is not
definition

Why do you think you need this line? The compiler is quite apparent
that it doesn't like it.
template<typename Vertex>
ostream & operator<<(ostream& o, const Tree<Vertex>& t ){
//o << t.fg << endl;
return o;
}

OK, a definition.
template<typename Vertex>
void Tree<Vertex>::test(){ cout << "Namasivayah" << endl;}

OK, a generic definition.
template class Tree<Vertex>;

Uh... What's that? Looks a bit like an explicit instantiation. Do you
have the type 'Vertex' which is concrete?
template ostream& operator<<<Vertex>(ostream& o, const Tree<Vertex>&
t );

OK, looks like an explicit instantiation.
template void Tree<Vertex>::test<Vertex>();//error: variable or field
‘test’ declared void, expected `;' before ‘<’ token

Well, 'test' is not a template. 'Tree' is a template. And I am not
sure you can explicitly instantiate template members.

What is it you're trying to accomplish?

V
 
S

suresh.amritapuri

suresh.amritapuri wrote:

 > [..]
Thanks, but reading the faq did not help me :(

Mmm... Didn't it?  You don't have linker errors any longer, do you?

 > Here is my modification


and still g++ cribs. has indicated error against the two offending
lines
Any suggestions pls?
suresh
//tree.h
#include "factorGraph.h"
template <typename Vertex>
class Tree{
public:
   Tree(FactorGraph f):fg(f){}
   //Vertex root(){return root;} //returns the root
   void root(Vertex rt){rootVertex=rt;} //sets the root
   friend ostream & operator<< (ostream& o, const Tree<Vertex>& );
   void test();
private:
   Vertex rootVertex;
   FactorGraph fg;
};
//#include "tree.cpp"
#endif /* TREE_H_ */
//tree.cpp
#include "tree.h"
template<typename Vertex> class Tree;

Uh... Why do you need this [re-]declaration?  Doesn't the header contain
the definition of the 'Tree' class template?
template<typename Vertex> ostream & operator<<(ostream& o, const
Tree<Vertex>& t );

OK, a declaration.
template<typename Vertex> void Tree<Vertex>::test(void); //error:
declaration of ‘void Tree<Vertex>::test()’ outside of class is not
definition

Why do you think you need this line?  The compiler is quite apparent
that it doesn't like it.


template<typename Vertex>
ostream & operator<<(ostream& o, const Tree<Vertex>& t ){
   //o << t.fg << endl;
   return o;
}

OK, a definition.


template<typename Vertex>
void Tree<Vertex>::test(){ cout << "Namasivayah" << endl;}

OK, a generic definition.


template class Tree<Vertex>;

Uh... What's that?  Looks a bit like an explicit instantiation.  Do you
have the type 'Vertex' which is concrete?


template ostream& operator<<<Vertex>(ostream& o, const Tree<Vertex>&
t );

OK, looks like an explicit instantiation.
template void Tree<Vertex>::test<Vertex>();//error: variable or field
‘test’ declared void, expected `;' before ‘<’ token

Well, 'test' is not a template.  'Tree' is a template.  And I am not
sure you can explicitly instantiate template members.

What is it you're trying to accomplish?

Hi Victor,

thanks for replying, but I am still in trouble. I have put the
complete code, with my intentions below. I have removed the test()
because I just added it for testing only.

typedef adjacency_list<vecS, vecS, undirectedS, vertex_properties,
edge_properties> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex; //boost graph
library

//these lines are added as suggested in C++ FAQ 35.16
template<typename Vertex> class Tree;
template<typename Vertex> ostream & operator<<(ostream& o, const
Tree<Vertex>& t );

template <typename Vertex>
class Tree{
public:
Tree(FactorGraph f):fg(f){}
Vertex root(){return root;} //returns the root
void root(Vertex rt){rootVertex=rt;} //sets the root
friend ostream & operator<< <>(ostream& o, const Tree<Vertex>& ); //
added <> after operator as suggested in FAQ 35

private:
Vertex rootVertex;
FactorGraph fg;
};
//#include "tree.cpp"
#endif /* TREE_H_ */

//my main.cpp
int main(){
//relevant portion only
FactorGraph fg(factors,vars,edges);
fg.sumProduct();
fg.displayMarginals();
Tree<vertex_properties> mytree(fg);
cout << mytree << endl; //Error: undefined reference to
`std::basic_ostream said:
&, Tree<vertex_properties> const&)'
collect2: ld returned 1 exit status
}

Hoping to hear from you,
regards
suresh
 
V

Victor Bazarov

suresh.amritapuri said:
suresh.amritapuri said:
Tree<vertex_properties> mytree(fg);
cout << mytree << endl; //Error: undefined reference to
`std::basic_ostream said:
&, Tree<vertex_properties> const&)'
collect2: ld returned 1 exit status
}

Your supposedly complete code does not contain any *definition* of the
operator<< template or otherwise. It contains one namespace declaration
of it and one friend declaration (when you make that operator a friend
of the class template Tree). Why are you surprised that the linker
cannot find it? Give the linker a definition of that operator.

V
 
S

suresh.amritapuri

suresh.amritapuri said:
suresh.amritapuri wrote:
 > [..]
Tree<vertex_properties> mytree(fg);
cout << mytree << endl; //Error: undefined reference to

collect2: ld returned 1 exit status
}

Your supposedly complete code does not contain any *definition* of the
operator<< template or otherwise.  It contains one namespace declaration
of it and one friend declaration (when you make that operator a friend
of the class template Tree).  Why are you surprised that the linker
cannot find it?  Give the linker a definition of that operator.

Ooops, i missed to type the defn from my tree.cpp file. Here it is:
#include tree.h
template<typename Vertex>
ostream & operator<<(ostream& o, const Tree<Vertex>& t ){
cout << "Namasivayah" << endl;
//o << t.fg << endl;
return o;
}

Now where is the error?
thanks
suresh
 
Ad

Advertisements

V

Victor Bazarov

suresh.amritapuri said:
[..]
Ooops, i missed to type the [..]

Now where is the error?
thanks
suresh

suresh,

I am sorry, you're probably going to have to start over. I cannot hunt
for bits and pieces of your code across different posts. Please read
FAQ 5.8 and follow its recommendations, OK? Good luck!

V
 
M

Michael Tsang

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

suresh.amritapuri said:
Hi,

This is my code:
//tree.h file
#ifndef TREE_H_
#define TREE_H_
#include "factorGraph.h"
template <typename Vertex>
class Tree{
public:
Tree(FactorGraph f):fg(f){}
Vertex root(){return root;} //returns the root
void root(Vertex rt){rootVertex=rt;} //sets the root
friend ostream & operator<<(ostream& o, const Tree<Vertex>& );
void test();

private:
Vertex rootVertex;
FactorGraph fg;
};
#endif /* TREE_H_ */

In short:
Place all function definition templates inside headers.

In long:
A class template is NOT a class. However, when all template parameters are
passed to a class template, it IS a class. The normal compile-link mechanism
does not work. In terms of implementation, When you include a header which
contains a class definition template (like your tree.h) in a translation
unit and you use that template to generate a class, the compiler only sees
the function declaration but not the definition. When you compile the
translation unit which contains the function definition template, the
compiler outputs no object code because there is really no code in it.
(Remember that a function definition template is not a function definition.
It is just a template that, provided the parameters, the compiler can
generate code by substituting the template parameters into the template and
compile the resulting generated code.) Therefore, at link time, the function
definitions cannot be found and the link process fails.

Example:

// swap.hpp
#ifndef SWAP_HPP
# define SWAP_HPP

// declaration for swap
template<class T>
void swap(T &a, T &b);

#endif

// swap.cpp
#include <algorithm>
#include "swap.hpp"

// definition for swap<T>
template<class T>
void swap<T>(T &a, T &b) {
T c = std::move(a);
a = std::move(b);
b = std::move(c);
}

// main.cpp
#include "swap.cpp"

int main() {
int a = 0;
int b = 1;
swap(a, b);
}

In the above, compiling the *.cpp files generates the following symbols in
the object file (T means defined symbol, E means external symbol to be
resolved):

swap.o:

main.o:
T main()
E swap<int>(int &, int &)

In the above case, swap.o actually contains NOTHING. Therefore, in the
linking process, the linker cannot find the definition of swap<T>(T &, T &)
and the linking fails.

Solution 1 (place the code in the header):

// swap.hpp
#ifndef SWAP_HPP
# define SWAP_HPP
# include <algorithm>

template<class T>
void swap<T>(T &a, T &b) {
T c = std::move(a);
a = std::move(b);
b = std::move(c);
}

#endif

// main.cpp
#include "swap.cpp"

int main() {
int a = 0;
int b = 1;
swap(a, b);
}

Here, only 1 TU is compiled, all fine.

Solution 2 (forced instantiation of the template):

// swap.hpp
#ifndef SWAP_HPP
# define SWAP_HPP

// declaration for swap
template<class T>
void swap(T &a, T &b);

#endif

// swap.cpp
#include <algorithm>
#include "swap.hpp"

// definition for swap<T>
template<class T>
void swap<T>(T &a, T &b) {
T c = std::move(a);
a = std::move(b);
b = std::move(c);
}

// dummy function
namespace {
void dummy() {
int a = 0;
int b = 1;
swap(a, b);
}
}

// main.cpp
#include "swap.cpp"

int main() {
int a = 0;
int b = 1;
swap(a, b);
}

In this case, the template must be instantiated when compiling swap.cpp
because of dummy():

swap.o:
E std::move(int &&)
T swap<int>(int &, int &)
T __swap_cpp_internal::dummy()

main.o:
T main()
E swap<int>(int &, int &)

Therefore, the external symbol in main.o match that in swap.o, and the
external symbol in swap.o can be found in the STL. Therefore, the link
process succeeds.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAksrn0IACgkQG6NzcAXitM9dwQCfUxZjFG0YAP2Z6Ln2h1ixSvdS
SLYAnjkINxe4bHGjhOMedxGHCiYs6NWG
=HU0W
-----END PGP SIGNATURE-----
 
S

suresh.amritapuri

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1



suresh.amritapuriwrote:



In short:
Place all function definition templates inside headers.

In long:
A class template is NOT a class. However, when all template parameters are
passed to a class template, it IS a class. The normal compile-link mechanism
does not work. In terms of implementation, When you include a header which
contains a class definition template (like your tree.h) in a translation
unit and you use that template to generate a class, the compiler only sees
the function declaration but not the definition. When you compile the
translation unit which contains the function definition template, the
compiler outputs no object code because there is really no code in it.
(Remember that a function definition template is not a function definition.
It is just a template that, provided the parameters, the compiler can
generate code by substituting the template parameters into the template and
compile the resulting generated code.) Therefore, at link time, the function
definitions cannot be found and the link process fails.

Example:

// swap.hpp
#ifndef SWAP_HPP
# define SWAP_HPP

// declaration for swap
template<class T>
void swap(T &a, T &b);

#endif

// swap.cpp
#include <algorithm>
#include "swap.hpp"

// definition for swap<T>
template<class T>
void swap<T>(T &a, T &b) {
        T c = std::move(a);
        a = std::move(b);
        b = std::move(c);

}

// main.cpp
#include "swap.cpp"

int main() {
        int a = 0;
        int b = 1;
        swap(a, b);

}

In the above, compiling the *.cpp files generates the following symbols in
the object file (T means defined symbol, E means external symbol to be
resolved):

swap.o:

main.o:
T       main()
E       swap<int>(int &, int &)

In the above case, swap.o actually contains NOTHING. Therefore, in the
linking process, the linker cannot find the definition of swap<T>(T &, T &)
and the linking fails.

Solution 1 (place the code in the header):

// swap.hpp
#ifndef SWAP_HPP
# define SWAP_HPP
# include <algorithm>

template<class T>
void swap<T>(T &a, T &b) {
        T c = std::move(a);
        a = std::move(b);
        b = std::move(c);

}

#endif

// main.cpp
#include "swap.cpp"

int main() {
        int a = 0;
        int b = 1;
        swap(a, b);

}

Here, only 1 TU is compiled, all fine.

Solution 2 (forced instantiation of the template):

// swap.hpp
#ifndef SWAP_HPP
# define SWAP_HPP

// declaration for swap
template<class T>
void swap(T &a, T &b);

#endif

// swap.cpp
#include <algorithm>
#include "swap.hpp"

// definition for swap<T>
template<class T>
void swap<T>(T &a, T &b) {
        T c = std::move(a);
        a = std::move(b);
        b = std::move(c);

}

// dummy function
namespace {
        void dummy() {
                int a = 0;
                int b = 1;
                swap(a, b);
        }

}

// main.cpp
#include "swap.cpp"

int main() {
        int a = 0;
        int b = 1;
        swap(a, b);

}

In this case, the template must be instantiated when compiling swap.cpp
because of dummy():

swap.o:
E       std::move(int &&)
T       swap<int>(int &, int &)
T       __swap_cpp_internal::dummy()

main.o:
T       main()
E       swap<int>(int &, int &)

Therefore, the external symbol in main.o match that in swap.o, and the
external symbol in swap.o can be found in the STL. Therefore, the link
process succeeds.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAksrn0IACgkQG6NzcAXitM9dwQCfUxZjFG0YAP2Z6Ln2h1ixSvdS
SLYAnjkINxe4bHGjhOMedxGHCiYs6NWG
=HU0W
-----END PGP SIGNATURE-----

Hi,

I am able to make the code working by including the definitions of the
friend function inside the header file. But Faq 35.16 suggests that it
can be done otherwise, but it didnot work for me. Here is my
"complete" code.

//tree.h

struct message {
bool isFactor; //message type
Factor f;
message(){};
message(bool isfactor);
message(bool isfactor, Factor f);
message operator*(const message);
friend ostream & operator<<(ostream&,const message &);
};

struct vertex_properties {
message ownMessage;
vertexName name;
vector<vertexName> adjV;
nameMsgMap msgFromNs;//indexed by vertex name.

vector<vertexName> readyToSend()const;
message msgTo(const vertex_properties v)const;//calculate message for
Vertexname V
bool sentMessageTo(const message m, vertex_properties & dest);
nameMsgMapSz checkMessagesSize()const; //for debugging returns the
size of the adj messages map size
};

struct edge_properties {
set<vertexName> count;
};


typedef adjacency_list<vecS, vecS, undirectedS, vertex_properties,
edge_properties> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;

//suggested by FAQ 35.16
template<typename Vertex> class Tree;
template<typename Vertex>
ostream & operator<< (ostream& o, const Tree<Vertex>& t );

template <typename Vertex>
class Tree{
public:
Tree(FactorGraph f):fg(f){}
Vertex root(){return root;} //returns the root
void root(Vertex rt){rootVertex=rt;} //sets the root
friend ostream & operator<< <>(ostream& o, const Tree<Vertex>& );
void add_vertex(Vertex vx);

private:
Vertex rootVertex;
FactorGraph fg;
};
#include "tree.cpp" // with this everything is fine. But is there any
way without doing this?
//end of tree.h

//tree.cpp
#include "tree.h"

//suggested by FAQ 35.16
template<typename Vertex> class Tree;
template<typename Vertex>
ostream & operator<< (ostream& o, const Tree<Vertex>& t );

template<typename Vertex>
ostream & operator<< (ostream& o, const Tree<Vertex>& t ){
cout << "Namasivayah" << endl;
//o << t.fg << endl;
return o;
}


template<typename Vertex>
void Tree<Vertex>::add_vertex(Vertex vx){
add_vertex(vx,fg.g);
}
//end of tree.cpp

//main.cpp

int main()
{
//relevant lines
FactorGraph fg(factors,vars,edges);
fg.sumProduct();
fg.displayMarginals();

Tree<vertex_properties> mytree(fg);
cout << mytree << endl; //if i do not include tree.cpp inside tree.h,
linker cribs here.
}
//end of main.cpp

Thanks for the help,
suresh
 
V

Victor Bazarov

suresh.amritapuri said:
[..]
I am able to make the code working by including the definitions of the
friend function inside the header file. But Faq 35.16 suggests that it
can be done otherwise, but it didnot work for me. Here is my
"complete" code.

[..]

Let's make it very simple to start.

------------------------------------------------ foo.h
template<class T> void foo(T t); // declaration
------------------------------------------------ foo.cpp
#include <foo.h>
#include <typeinfo>
#include <iostream>

template<class T> void foo(T t) // definition
{
std::cout << "foo(" << typeid(T).name() << ")\n";
}

template void foo<int>(int); // explicit instantiation
template void foo<double>(int); // explicit instantiation
------------------------------------------------ main.cpp
#include <foo.h>

int main()
{
foo(42); // OK
foo(3.14159); // OK
foo('a'); // will not link : foo<char> undefined
}
----------------------------------------------------------

Now, the code above is untested, but conveys the general idea of how
templates can be made "available" without including the definitions of
the functions into the header: the explicit instantiation mechanism.

V
 
S

suresh.amritapuri

suresh.amritapuri said:
Let's make it very simple to start.

------------------------------------------------ foo.h
template<class T> void foo(T t); // declaration
------------------------------------------------ foo.cpp
#include <foo.h>
#include <typeinfo>
#include <iostream>

template<class T> void foo(T t) // definition
{
    std::cout << "foo(" << typeid(T).name() << ")\n";

}

template void foo<int>(int);    // explicit instantiation
template void foo<double>(int); // explicit instantiation
------------------------------------------------ main.cpp
#include <foo.h>

int main()
{
     foo(42);      // OK
     foo(3.14159); // OK
     foo('a'); // will not link : foo<char> undefined}

----------------------------------------------------------

Now, the code above is untested, but conveys the general idea of how
templates can be made "available" without including the definitions of
the functions into the header: the explicit instantiation mechanism.


thanks Victor, I was able to do the same with non friend functions. I
mean I could successfully compile and link. Linker failed only in the
friend function case. Your example has only non friend functions....

suresh
 
Ad

Advertisements

V

Victor Bazarov

suresh.amritapuri said:
suresh.amritapuri said:
Let's make it very simple to start.
[..]

thanks Victor, I was able to do the same with non friend functions. I
mean I could successfully compile and link. Linker failed only in the
friend function case. Your example has only non friend functions....

Did you even try?

------------------------------------------------ foo.h
template<class T> void foo(T t); // declaration

template<class T> class Foo
{
private:
friend void foo<>(T); // here is the friend declaration
Foo(T);
};
------------------------------------------------ foo.cpp
#include "foo.h"
#include <typeinfo>
#include <iostream>

template<class T> void foo(T t) // definition
{
Foo<T> ft(t); // should be fine for all - we're friends
std::cout << "foo(" << typeid(ft).name() << ")\n";
}

template<class T> Foo<T>::Foo(T)
{
std::cout << "Constructor Foo(" << typeid(T).name() << ")\n";
}

template void foo<int>(int); // explicit instantiation
template void foo<double>(double); // explicit instantiation
template void foo<char>(char); // explicit instantiation
------------------------------------------------ main.cpp
#include "foo.h"

int main()
{
foo(666);
foo(6.66);
foo('L');
}
----------------------------------------------------------

In the example above even the Foo c-tor is in a C++ file since it's not
used from 'main'...

V
 
S

suresh.amritapuri

------------------------------------------------ foo.h
template<class T> void foo(T t); // declaration

template<class T> class Foo
{
private:
    friend void foo<>(T); // here is the friend declaration
    Foo(T);};

------------------------------------------------ foo.cpp
#include "foo.h"
#include <typeinfo>
#include <iostream>

template<class T> void foo(T t) // definition
{
    Foo<T> ft(t); // should be fine for all - we're friends
    std::cout << "foo(" << typeid(ft).name() << ")\n";

}

template<class T> Foo<T>::Foo(T)
{
    std::cout << "Constructor Foo(" << typeid(T).name() << ")\n";

}

template void foo<int>(int);    // explicit instantiation
template void foo<double>(double); // explicit instantiation
template void foo<char>(char);  // explicit instantiation
------------------------------------------------ main.cpp
#include "foo.h"

int main()
{
     foo(666);
     foo(6.66);
     foo('L');}

----------------------------------------------------------
Hi Victor,

I had tried both versions of your code (with and without friends).
Both are working in my machine. (in your version without friends,
there was a typo which you have corrected in the next version).
However, linker is still complaining about my friend function. As your
code was working, I looked at the symbols present in the object files
created and found something interesting.

Symbol from main.o: U std::eek:stream& operator<< <vertex_properties>
(std::eek:stream&, Tree<vertex_properties> const&)

Its correct.

However, in my tree.o the following symbol is present and I do not
know how this came up.
00000000 W std::eek:stream& operator<< <unsigned int>(std::eek:stream&,
Tree<unsigned int> const&)

I do not understand how this symbol is created in the object file.
Where is this unsigned int coming from?? Instead of unsigned int, it
should have been vertex_properties.

//tree.cpp
#include "tree.h"

template<typename Vertex>
ostream & operator<< (ostream& o, const Tree<Vertex>& t ){
cout << "Namasivayah" << endl;
//o << t.fg << endl;
return o;
}


template<typename Vertex>
void Tree<Vertex>::add_vertex(Vertex vx){
add_vertex(vx,fg.g);
}

template ostream& operator<< <Vertex> (ostream&, const
Tree<Vertex>&);//explicit instatiation - as suggested by Victor
Bazarov

//end of tree.cpp

//tree.h
//from another include file, i have the following
struct message {
bool isFactor; //message type
Factor f;
message(){};
message(bool isfactor);
message(bool isfactor, Factor f);
message operator*(const message);
friend ostream & operator<<(ostream&,const message &);

};

struct vertex_properties {
message ownMessage;
vertexName name;
vector<vertexName> adjV;
nameMsgMap msgFromNs;//indexed by vertex name.

vector<vertexName> readyToSend()const;
message msgTo(const vertex_properties v)const;//calculate
message for Vertexname V
bool sentMessageTo(const message m, vertex_properties & dest);
nameMsgMapSz checkMessagesSize()const; //for debugging returns
the size of the adj messages map size

};

struct edge_properties {
set<vertexName> count;

};

typedef adjacency_list<vecS, vecS, undirectedS, vertex_properties,
edge_properties> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;

//actual tree.h starts from here.

template<typename Vertex> class Tree;
template<typename Vertex>
ostream & operator<< (ostream& o, const Tree<Vertex>& t );

template <typename Vertex>
class Tree{
public:
Tree(FactorGraph f):fg(f){}
Vertex root(){return root;} //returns the root
void root(Vertex rt){rootVertex=rt;} //sets the root
friend ostream & operator<< <>(ostream& o, const Tree<Vertex>& );
void add_vertex(Vertex vx);

private:
Vertex rootVertex;
FactorGraph fg;
};

#endif /* TREE_H_ */
//end of tree.h

//main.cpp

int main()
{
//relevant lines
FactorGraph fg(factors,vars,edges);
fg.sumProduct();
fg.displayMarginals();

Tree<vertex_properties> mytree(fg);
cout << mytree << endl; //linker cribs here.
}

//end of main.cpp

suresh
 
Ad

Advertisements

S

suresh.amritapuri

Hi Victor,

I had tried both versions of your code (with and without friends).
Both are working in my machine. (in your version without friends,
there was a typo which you have corrected in the next version).
However, linker is still complaining about my friend function. As your
code was working, I looked at the symbols present in the object files
created and found something interesting.

Symbol from main.o: U std::eek:stream& operator<< <vertex_properties>
(std::eek:stream&, Tree<vertex_properties> const&)

Its correct.

However, in my tree.o the following symbol is present and I do not
know how this came up.
00000000 W std::eek:stream& operator<< <unsigned int>(std::eek:stream&,
Tree<unsigned int> const&)

I do not understand how this symbol is created in the object file.
Where is this unsigned int coming from?? Instead of unsigned int, it
should have been vertex_properties.

//tree.cpp
#include "tree.h"

template<typename Vertex>
ostream & operator<< (ostream& o, const Tree<Vertex>& t ){
        cout << "Namasivayah" << endl;
        //o << t.fg << endl;
        return o;

}

template<typename Vertex>
void Tree<Vertex>::add_vertex(Vertex vx){
        add_vertex(vx,fg.g);

}

template ostream& operator<< <Vertex> (ostream&, const
Tree<Vertex>&);//explicit instatiation - as suggested by Victor
Bazarov

//end of tree.cpp

//tree.h
//from another include file, i have the following
struct message {
        bool isFactor; //message type
        Factor f;
        message(){};
        message(bool isfactor);
        message(bool isfactor, Factor f);
        message operator*(const message);
        friend ostream & operator<<(ostream&,const message &);

};

struct vertex_properties {
        message ownMessage;
        vertexName name;
        vector<vertexName> adjV;
        nameMsgMap msgFromNs;//indexed by vertex name.

        vector<vertexName> readyToSend()const;
        message msgTo(const vertex_properties v)const;//calculate
message for Vertexname V
        bool sentMessageTo(const message m, vertex_properties & dest);
        nameMsgMapSz checkMessagesSize()const; //for debugging returns
the size of the adj messages map size

};

struct edge_properties {
        set<vertexName> count;

};

typedef adjacency_list<vecS, vecS, undirectedS, vertex_properties,
                edge_properties> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;

//actual tree.h starts from here.

template<typename Vertex> class Tree;
template<typename Vertex>
ostream & operator<< (ostream& o, const Tree<Vertex>& t );

template <typename Vertex>
class Tree{
public:
        Tree(FactorGraph f):fg(f){}
        Vertex root(){return root;} //returns the root
        void root(Vertex rt){rootVertex=rt;} //sets the root
        friend ostream & operator<< <>(ostream& o, const Tree<Vertex>& );
        void add_vertex(Vertex vx);

private:
        Vertex rootVertex;
        FactorGraph fg;

};

#endif /* TREE_H_ */
//end of tree.h

//main.cpp

int main()
{
//relevant lines
FactorGraph fg(factors,vars,edges);
fg.sumProduct();
fg.displayMarginals();

Tree<vertex_properties> mytree(fg);
cout << mytree << endl; //linker cribs here.

}

//end of main.cpp

suresh

Ok, finally I resolved it by doing explicit instantiation properly.
But then let me ask you another question. The explicit instantiation
is done in the .cpp file of the member function definitions. But in
general the user has no access to this file right? So, with what type,
user is going to use the template, is not known a priori. So how can
explicit instantiations be when the class and function definitions are
in some other file which we dont have access to. I am also curios,
what is done in the standard library, for example vector class. Do
they also include the whole definition inside the .h file?

Victor, thanks for your patience and support,

with warm regards
suresh
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top