I'm getting "Unresolved external symbols" for the following code:
template <int n> class Fibo
{
private:
int pre, cur, next, tmp;
public:
Fibo() : pre(1), cur(1), next(2), tmp(0) {}
int get()
{
if(n == 0 || n == 1) return 1;
for(int i = 2; i < n; ++i)
{
next = pre + cur;
tmp = cur;
cur = next;
pre = tmp;
} return pre + cur;
}
friend ostream& operator<< (ostream& out, Fibo<n>& f);
};
template<int n>
ostream& operator<< (ostream& out, Fibo<n>& f)
{
out << f.get();
return out;
}
int main()
{
Fibo<5> a;
cout << a << endl;
cin.get();
}
I get this compilation error when I'm trying to print a:
cout << a << endl;. When I'm printing "normaly", i.e. cout << a.get() << endl, no errors popped.
I know that Unresolved external symbols error are associated with declared function that didn't implemented. is that the case in my code? I can't find it.
There are a couple ways to handle this:
template <int n> class Fibo ; // Forward declaration
// Definition, you could also forward declare here and define after the class
template<int n>
ostream& operator<< (ostream& out, Fibo<n>& f)
{
out << f.get();
return out;
}
template <int n> class Fibo
{
// Don't forget <> to tell its a template
friend ostream& operator<< <> (ostream& out, Fibo<n>& f);
};
The above way is verbose, but you could also define the friend in-class:
template <int n> class Fibo
{
// Note this is not a template
friend ostream& operator<< (ostream& out, Fibo& f)
{
out << f.get();
return out;
}
};
The in-class definition will define a friend function for each instantiation, i.e. Fibo<1>, Fibo<2>, etc.
GCC compiler messages:
test.C:22:57: warning: friend declaration ‘std::ostream& operator<<(std::ostream&,
Fibo<n>&)’ declares a non-template function [-Wnon-template-friend]
test.C:22:57: note: (if this is not what you intended, make sure the function
template has already been declared and add <> after the function name here)
Pretty self-explanatory I think.
Related
I am trying to overload the output operator to print from a class with a template that uses non-type values. However, I keep getting the error
"unexpected token 'identifier', expected ';'"
in the operator's function body. How do I fix either my friend declaration or my operator overload definition to avoid this error?
template <int N, int M> class Screen {
friend std::ostream& operator<< (std::ostream&, const Screen&);
public:
Screen(): width(N), height(M) {}
int width = 0;
int height = 0;
};
template <int N, int M>
std::ostream& operator<< (std::ostream& os, const Screen<N, M>& a)
{
os << a.width << ":" a.height;
return os;
}
You have forgotten a <<
// ..................VV
os << a.width << ":" << a.height;
I am working on a template Graph data structure, which is an STL vector of GraphNode objects. I defined the GraphNode class nested inside the Graph class and when I invoke the overloaded insertion operator for the GraphNode object inside the overloaded insertion operator for the Graph object Visual Studio 15 (C++) reports,
(30): warning C4346: 'myGraph<T>::myGraphNode': dependent name is not a type
(30): note: prefix with 'typename' to indicate a type
(30): error C2061: syntax error: identifier 'myGraphNode'
(33): error C2805: binary 'operator <<' has too few parameters
template <typename T>
ostream& operator<<(ostream& strm, const myGraph<T>::myGraphNode& gn)
adding the word typename to the second formal parameter
template <typename T>
ostream& operator<<(ostream& strm, typename const myGraph<T>::myGraphNode& gn)
The compiler generates the following error
(49): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const myGraph<int>::myGraphNode' (or there is no acceptable conversion)
I get the same error if I typename const .... or const typename ...
For completeness here is all the code somewhat simplified for this post.
Thanks for any help
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef unsigned int uint;
template <typename T>
class myGraph {
public:
class myGraphNode {
public:
myGraphNode(T val = T());
T mData;
}; // end class myGraphNode
myGraph();
uint addGraphNode(T data);
vector<myGraphNode> mGraphNodes;
}; // end class myGraph
// myGraphNode
template <typename T>
myGraph<T>::myGraphNode::myGraphNode(T val) : mData(val) {}
template <typename T>
ostream& operator<<(ostream& strm, typename const myGraph<T>::myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}
// myGraph
template <typename T>
myGraph<T>::myGraph() {}
template <typename T>
uint myGraph<T>::addGraphNode(T data) {
myGraph<T>::myGraphNode node(data);
mGraphNodes.push_back(node);
}
template <typename T>
ostream& operator<<(ostream& strm, const myGraph<T>& g) {
for (uint i = 0; i < g.mGraphNodes.size(); ++i)
cout << g.mGraphNodes[i] << endl;
return strm;
} // end operator<<(...)
int main()
{
myGraph<int> g;
g.addGraphNode(3);
g.addGraphNode(5);
cout << g << endl;
return 0;
}
Firstly, the correct syntax for parameter declaration should be
template <typename T>
ostream& operator<<(ostream& strm, const typename myGraph<T>::myGraphNode& gn)
// ~~~~~ ~~~~~~~~
Refer here for more informations.
Secondly, with the above declaration, when trying to call it in operator<< for myGraph<T> like cout << g.mGraphNodes[i] << endl;, T can't be deduced because of non-deduced contexts):
The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
That means, you have to specify the template argument explicitly for it, e.g.
operator<<<T>(strm, g.mGraphNodes[i]);
// ~~~
But it's ugly. For your case, you can just implement operator<< for myGraph<T> like
template <typename T>
ostream& operator<<(ostream& strm, const myGraph<T>& g) {
for (uint i = 0; i < g.mGraphNodes.size(); ++i)
cout << g.mGraphNodes[i].mData << endl;
return strm;
}
BTW: You should give a return value for myGraph<T>::addGraphNode.
Template type deduction only matches patterns. It doesn't invert dependent types, because that (in the general case) is impossible.
The way to solve this problem is a technique I call Koenig operators.
friend std::ostream& operator<<(std::ostream& strm, const myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}
Put this in the body of myGraphNode.
class myGraphNode {
public:
myGraphNode(T val = T());
T mData;
friend std::ostream& operator<<(std::ostream& strm, const myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}
}; // end class myGraphNode
This is a non-template operator injected into surrounding namespace (only) reachable via ADL. Which is fancy words for "it just works".
I'm trying to make << output an entire matrix which I wrote a template for. Not sure why this isn't working, the error is:
error: no match for 'operator[]' (operand types are 'matrix<int' and 'int')
candidate is:
matrix<Comparable> matrix<Comparable>::operator[](matrix<Comparable>&) [with Comparable = int]|
no known conversion for argument 1 from 'int' to 'matrix<int>&'|
which refers to this line: o << rhs[ i ][ j ]. Am I supposed to overload [ ] as well?
matrix.h:
template <typename Comparable>
class matrix
{
private:
size_t num_cols_;
size_t num_rows_;
Comparable **array_;
public:
friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
size_t NumRows();
size_t NumCols();
};
matrix.cpp:
template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs){
size_t c = rhs.NumRows();
size_t d = rhs.NumCols();
for (int i = 0; i < c; i++){
for (int j = 0; j < d; j++){
o << rhs[i][j]; //error
}
}
}
template <typename Comparable>
size_t matrix<Comparable>::NumRows(){
return num_rows_;
}
template <typename Comparable>
size_t matrix<Comparable>::NumCols(){
return num_cols_;
}
And probably irrelevant but I implemented the matrix like this:
array_ = new Comparable*[num_rows_];
for (int i = 0; i < num_rows_; i++){
array_[i] = new Comparable[num_cols_];
Your function signatures don't match:
ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
is not
template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs);
Notice that one is not a template, and the other is. Also, the first has a const reference argument for rhs and the second has just a reference. This mismatch means the function you define isn't Matrix's friend, and so can't access the private (or protected members of Matrix)
What you want is to declare a templated function, and then inform the compiler that a single instantiation (say ostream& operator<<(ostream& out, const matrix<int>& val) ) is the single function you want to be friends with matrix<int>.
To do this, you need to declare that you want only a specific version of the function template, and to do that you need to declare the template, and to do that you need to declare the templated class.
Ultimately that whole chain of declarations might look something like this:
#include <iostream>
// forward declare the class so the compiler knows what's up at the
// templated operator<< declaration.
template <typename T>
class Foo;
// forward declare the templated operator<< so the compiler knows you're
// 'friend'ing a specific instantiation of this template in the
// class definition.
template <typename T>
std::ostream& operator<<(std::ostream& out, const Foo<T>& value);
template <typename T>
class Foo{
// declare the instantiation of the operator<< template that shares
// T with the class template to be a friend:
// operator<<<> can be separated out into operator<< <>
friend std::ostream& operator<<<>(std::ostream& out, const Foo<T>& value);
int bar_;
public:
Foo(int bar) : bar_{bar}{}
};
// now that you know the contents of `Foo<T>`, define the templated operator<<
template <typename T>
std::ostream& operator<<(std::ostream& out, const Foo<T>& value){
return std::cout << "Foo: " << value.bar_;
}
int main(){
Foo<int>
a{2},
b{3};
std::cout << a << '\n' << b;
}
Live on Coliru
You can read further on Template Friends on the C++ Super-FAQ.
You can declare a get function to access array_ instead of making it as an public member;
I've recently learned that there are two ways to declare a template friend class or function. For example, to declare a template friend class, you may do this
template <typename T>
class goo
{
template <typename T>
friend class foo;
};
or this
template <typename T>
class goo
{
friend class foo <T>;
};
These two declarations are in fact different. The former allows you to use any type of template friend class foo with any type of template friend class goo. Where as the latter only allows you to use the same type such that you may do foo<int> with goo<int> but not foo<int> with goo<char>.
In the header file below, I try to use the latter form of the declaration to make my template friend function friend std::ostream& operator<<(std::ostream&, const Array<T>&); more type-specific in an effort to make my program more encapsulated.
//ARRAY_H
#include <iostream>
#include "Animal.h"
const int DefaultSize = 3;
template <typename T> // declare the template and the paramenter
class Array // the class being parameterized
{
public:
Array(int itsSize = DefaultSize);
Array(const Array &rhs);
~Array() { delete[] pType; }
// operators
Array& operator=(const Array&);
T& operator[](int offSet) { return pType[offSet]; }
const T& operator[](int offSet) const { return pType[offSet]; }
// accessors
int GetSize() const { return itsSize; }
// friend function
friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);
private:
T *pType;
int itsSize;
};
template <typename T>
Array<T>::Array(int size = DefaultSize) :itsSize(size)
{
pType = new T[size];
for (int i = 0; i < size; i++)
pType[i] = static_cast<T>(0);
}
Array<Animal>::Array(int AnimalArraySize) :itsSize(AnimalArraySize)
{
pType = new Animal[AnimalArraySize];
}
template <typename T>
Array<T>::Array(const Array &rhs)
{
itsSize = rhs.GetSzie();
pType = new T[itsSize];
for (int i = 0; i < itsSize; i++)
pType[i] = rhs[i];
}
template <typename T>
Array<T>& Array<T>::operator=(const Array &rhs)
{
if (this == &rhs)
return *this;
delete[] pType;
itsSize = rhs.GetSize();
pType = new T[itsSize];
for (int i = 0; i < itsSize; i++)
pType[i] = rhs[i];
return *this;
}
template <typename T>
std::ostream& operator<<(std::ostream& output, const Array<T> &theArray)
{
for (int i = 0; i < theArray.GetSize(); i++)
output << "[" << i << "]" << theArray[i] << std::endl;
return output;
}
#endif
However, I receive a compiler error "error C2143: syntax error : missing ';' before '<'" for line 23 which is friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);.
When using the former form of the declaration by changing line 23 to this
template <typename T>
friend std::ostream& operator<<(std::ostream&, const Array<T>&);
My program executes without any errors.
I assume I cannot use the same syntax from type-specific template friend classes for type-specific template friend functions, or that I may be missing some kind of forward declaration. I've searched through stack-overflow and the closest topic I could find for this problem is here, but they only discuss type-specific template friend classes. I am unable to find a topic that discusses the correct syntax for using a template friend function in this way.
If this is a syntax error, what is the correct way to declare my type-specific template friend function? If this is not a syntax error, why will my program not compile?
Here are the rest of my project files for your reference. The desired behavior of my program is to show how a parametrized array uses a template to create multiple instances of different array types.
//ANIMAL_H
#ifndef ANIMAL_H
#define ANIMAL_H
#include <iostream>
class Animal
{
public:
// constructors
Animal();
Animal(int);
~Animal();
// accessors
int GetWeight() const { return itsWeight; }
void SetWeight(int theWeight) { itsWeight = theWeight; }
// friend operators
friend std::ostream& operator<<(std::ostream&, const Animal&);
private:
int itsWeight;
};
#endif
//ANIMAL.CPP
#include "Animal.h"
#include <iostream>
Animal::Animal() :itsWeight(0)
{
std::cout << "animal() ";
}
Animal::Animal(int weight) : itsWeight(weight)
{
std::cout << "animal(int) ";
}
Animal::~Animal()
{
std::cout << "Destroyed an animal...";
}
std::ostream& operator<<(std::ostream& theStream, const Animal& theAnimal)
{
theStream << theAnimal.GetWeight();
return theStream;
}
//MAIN.CPP
#include <iostream>
#include "Animal.h"
#include "Array.h"
void IntFillFunction(Array<int>& theArray);
void AnimalFillFunction(Array<Animal>& theArray);
int main()
{
Array<int> intArray;
Array<Animal> animalArray;
IntFillFunction(intArray);
AnimalFillFunction(animalArray);
std::cout << "intArray...\n" << intArray;
std::cout << "\nanimalArray...\n" << animalArray << std::endl;
std::cin.get();
return 0;
}
void IntFillFunction(Array<int>& theArray)
{
bool Stop = false;
int offset, value;
while (!Stop)
{
std::cout << "Enter an offset (0-9) and a value. ";
std::cout << "(-1 to stop): ";
std::cin >> offset >> value;
if (offset < 0)
break;
if (offset > 9)
{
std::cout << "***Please use values between 0 and 9.***\n";
continue;
}
theArray[offset] = value;
}
}
void AnimalFillFunction(Array<Animal>& theArray)
{
Animal *pAnimal;
for (int i = 0; i < theArray.GetSize(); i++)
{
pAnimal = new Animal(i * 10);
theArray[i] = *pAnimal;
delete pAnimal;
}
}
You need to declare the function template before you refer to a specialization as a friend.
// Forward declare class template.
template <typename T> class Array;
// Declare function template.
template <typename T>
std::ostream& operator<<(std::ostream& os, const Array<T>& arr);
template <typename T>
class Array
{
//...
friend std::ostream& operator<< <>(
std::ostream& os, const Array<T>& arr);
//...
};
You need a forward declaration of the function template (just as you need with a class template) in order to friend a specialization. Your code should be:
template <typename T>
std::ostream& operator<<(std::ostream& output, const Array<T> &theArray);
template <typename T>
class Animal
{
// ...
friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);
};
I am trying to overload operator<< in my code. If I comment out the lines where I try to use the << operator with my custom class, it compiles fine. The error almost looks like it doesn't like the c++ libraries (?).
All my research on this problem has stated that it is a linking problem. Most suggest using g++ instead of gcc. I am using g++ as my compiler, and I get this error still.
Code:
#include <iostream>
using namespace std;
//prototype the class and the functions
template<class T> class strange;
template<class T> ostream& operator<< (ostream& osObject, strange<T>& sObject);
//begin class
template <class T>
class strange
{
public:
// .... function prototypes go here.
strange(T x,T y);
friend ostream& operator<< <> (ostream& osObject, strange<T>& sObject);
private:
T a;
T b;
};
// .... your function definitions go here
template <class T>
strange<T>::strange(T first, T second){
a = first;
b = second;
}
template <class T>
ostream& operator<< (ostream& osObject, const strange<T>& sObject){
osObject << sObject.a << ", " << sObject.b;
return osObject;
}
int main()
{
strange<int> x1(4,6) , x2(12,2) ;
//strange<char> y1('m','n') , y2('m','n') ;
cout << "x1 = " << x1 << endl;
return 0;
}
Error:
test.cpp:(.text+0x7a): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& operator<< <int>(std::basic_ostream<char, std::char_traits<char> >&, strange<int>&)'
collect2: ld returned 1 exit status
Any idea what is causing this?
I made two changes, one to the friend definition, and one to the prototype. This should compile:
#include <iostream>
using namespace std;
//prototype the class and the functions
template<class T> class strange;
template<class T> ostream& operator<< (ostream& osObject, const strange<T>& sObject);
//begin class
template <class T>
class strange
{
public:
// .... function prototypes go here.
strange(T x,T y);
friend ostream& operator<< <> (ostream& osObject, const strange<T>& sObject);
private:
T a;
T b;
};
// .... your function definitions go here
template <class T>
strange<T>::strange(T first, T second){
a = first;
b = second;
}
template <class T>
ostream& operator<< (ostream& osObject, const strange<T>& sObject){
osObject << sObject.a << ", " << sObject.b;
return osObject;
}
int main()
{
strange<int> x1(4,6) , x2(12,2) ;
//strange<char> y1('m','n') , y2('m','n') ;
cout << "x1 = " << x1 << endl;
return 0;
}
And this compiles in clang, g++ and at ideone
To explain the issue, the compiler is looking at link time for a definition for:
std::ostream & operator<< <int>(std::ostream &, strange<int>&);
When you only have a definition for:
std::ostream & operator<< <int>(std::ostream &, strange<int> const &);
This is because of the miscommunication between your prototypes (both the explicit one and the friend) and your definition.