I have compiled the first version of code in Turbo-C and it compiles without any error. But when I compile this in Visual Studio or plain g++ from CommandLine, I get errors mentioned down in the post.
I did searched over internet and read some of the StackOverflow questions & MSDN LNK1120 problem docs. I found a way to fix the below code. However, didn't got the reason clearly. How can just a definition gets rid of that error. Syntactically the error prone code also look fine.
1) Error 2 error LNK1120: 1 unresolved externals
2) Error 1 error LNK2019: unresolved external symbol "void __cdecl
totalIncome(class Husband<int> &,class Wife<int> &)" (?totalIncome##YAXAAV?
$Husband#H##AAV?$Wife#H###Z) referenced in function _main
Note: Please watch out for arrows in program. I've explicitly put them. So, might not go through the complete program.
Error Prone Code:
#include <iostream>
using namespace std;
template<typename T> class Wife; // Forward declaration of template
template<typename T>
class Husband{
friend void totalIncome(Husband<T> &hobj, Wife<T> &wobj);
public:
Husband() = default;
Husband(T new_salary): salary{new_salary} {}
private:
T salary;
};
template<typename T>
class Wife{
friend void totalIncome(Husband<T> &hobj, Wife<T> &wobj);
public:
Wife() = default;
Wife(T new_salary): salary{new_salary} {}
private:
T salary;
};
template<typename T> void totalIncome(Husband<T> &hobj, Wife<T> &wobj) __
{ |
cout << "Total Income of Husband & Wife: "; |
cout << hobj.salary + wobj.salary; |
} |
---
int main()
{
Husband<int> h(40000);
Wife<int> w(90000);
totalIncome(h, w);
return 0;
}
but in the below case by just moving the definition up in the class, it runs perfectly fine. Why whats the reason?
Fixed Code:
#include <iostream>
using namespace std;
template<typename T> class Wife; // Forward declaration of template
template<typename T>
class Husband{
friend void totalIncome(Husband<T> &hobj, Wife<T> &wobj);
public:
Husband() = default;
Husband(T new_salary): salary{new_salary} {}
private:
T salary;
};
template<typename T>
class Wife{
friend void totalIncome(Husband<T> &hobj, Wife<T> &wobj) __
{ |
cout << "Total Income of Husband & Wife: "; | -- definition moved up here
cout << hobj.salary + wobj.salary; |
} __|
public:
Wife() = default;
Wife(T new_salary): salary{new_salary} {}
private:
T salary;
};
/*
template<typename T> void totalIncome(Husband<T> &hobj, Wife<T> &wobj) __
{ |
cout << "Total Income of Husband & Wife: "; |
cout << hobj.salary + wobj.salary; |
} |
---
*/
int main()
{
Husband<int> h(40000);
Wife<int> w(90000);
totalIncome(h, w);
return 0;
}
First, let's cut this down to a minimal example that reproduces the issue:
template<typename T>
class Husband{
friend void totalIncome(Husband<T> &);
};
template<typename T> void totalIncome(Husband<T> &hobj)
{}
int main()
{
Husband<int> h;
totalIncome(h);
}
This leads to a similar linker error. For example, using clang++:
/tmp/main-fb41c4.o: In function `main':
main.cpp:(.text+0xd): undefined reference to `totalIncome(Husband&)'
The underlying issue is the same as the one in Overloaded arithmetic operators on a template causing an unresolved external error and in Strange behavior of templated operator<<. Hence, I'll base my answer here on my answer from the second question.
Friend function declarations
In the class template Husband, there is a friend-declaration of the function totalIncome:
friend void totalIncome(Husband<T> &);
A friend function declaration looks up the name of the declared function (here: totalIncome) in the surrounding scopes up to and including the innermost enclosing namespace. If a declaration of that name is found, the declared entity is befriended:
class Husband;
void totalIncome(Husband&); // (A)
class Husband{
friend void totalIncome(Husband&); // befriends (A)
};
If no declaration of the name is found, a new function is declared in the innermost enclosing namespace:
class Husband{
friend void totalIncome(Husband&); // declares and befriends ::totalIncome
};
void totalIncome(Husband&); // friend of class Husband
If the function is only declared via the friend function declaration (and there is no later declaration in the enclosing namespace), the function can only be found via Argument-Dependent Lookup.
Befriending a function in a class template
The issue in the OP's code is that there is a class template involved:
template<typename T>
class Husband{
friend void totalIncome(Husband<T> &);
};
The rules stay the same: No declaration of totalIncome is found. Since the signature of the friend declaration depends on the template parameter of the class template, every instantiation of Husband will introduce a new function in the enclosing namespace. (If the friend declaration did not depend on a template parameter, you'd get a redeclaration with every instantiation of Husband.) For example, if you instantiate Husband<int> and Husband<double>, you'll get two functions in the global namespace:
void totalIncome(Husband<int> &);
void totalIncome(Husband<double> &);
Note that these are two unrelated functions, much like:
void totalIncome(int &);
void totalIncome(double &);
Overloading a function with a function template
You can overload an "ordinary" function with a function template:
void totalIncome(Husband<int> &); // (A)
template<typename T>
void totalIncome(Husband<T> &); // (B)
When calling the function via Husband<int> x; totalIncome(x);, the function template will produce an instantiation:
void totalIncome<int>(Husband<int> &); // (C), instantiated from (B)
And your overload set consists of two functions:
void totalIncome(Husband<int> &); // (A)
void totalIncome<int>(Husband<int> &); // (C)
All things equal, overload resolution will prefer the non-template function (A) over the function template specialization (C).
And this is what happens in the OP's code as well: There is a non-template function introduced by instantiating the class template Husband, and an unrelated function template. Overload resolution chooses the non-template function, and the linker complains that it doesn't have a definition.
Various solutions
The simplest solution is to define the friend function inside the class definition:
template<typename T>
class Husband{
friend void totalIncome(Husband<T> &){
// code here
}
};
A solution using forward-declarations:
template<typename T>
class Husband;
template<typename T>
void totalIncome(Husband<T> &);
template<typename T>
class Husband{
friend void totalIncome(Husband<T> &);
};
template<typename T> void totalIncome(Husband<T> &hobj)
{}
Here, the compiler can find the forward-declared function template and befriend a specialization of it, instead of declaring a new function. It might be worthwhile explicitly adding the template arguments:
template<typename T>
class Husband{
friend void totalIncome<T>(Husband<T> &);
};
Since this enforces that there is a prior declaration of the function template totalIncome.
A solution befriending the whole function template:
template<typename T>
class Husband{
template<typename U>
friend void totalIncome(Husband<U> &);
};
template<typename T> void totalIncome(Husband<T> &hobj)
{}
In this solution, the friend-declaration declares a function template, and the later declaration at namespace scope following the class' definition redeclares and defines this function template. All specializations of the function template will be befriended by all instantiations of Husband.
Related
I'm trying to write a template class which overloads operator==. I know how to get it inside the class:
template <typename T>
class Point
{
private:
T x;
public:
Point(T X) : x(X) {}
bool operator== (Point &cP)
{
return (cP.x == x);
}
};
But now I want to achieve this outside the template class. I've read this post:
error when trying to overload << operator and using friend function and add template declaration in my code:
template <typename> class Point;
template <typename T> bool operator== (Point<T>, Point<T>);
template <class T>
class Point
{
private:
T x;
public:
Point(T X) : x(X) {}
friend bool operator== (Point cP1, Point cP2);
};
template <class T>
bool operator== (Point<T> cP1, Point<T> cP2)
{
return (cP1.x == cP2.x)
}
However I still get a error: unresolved external symbol "bool __cdecl operator==(class Point<int>,class Point<int>)" (??8#YA_NV?$Point#H##0#Z) referenced in function _main
And when I take away friend from :
friend bool operator== (Point cP1, Point cP2);
and want it to be member function, there would be a another error:
too many parameters for this function
why?
#Kühl's answer is the most permissive approach to declare a templated friend function of a templated class. However, there is one unapparent side effect of this approach: All template instantiations of Point are friends with all template instantiations of operator==(). An alternative is to make only the instantiation with the same type of Point a friend. Which is done by adding a <T> in the friend declaration of operator==().
template <typename T> class Point;
template <typename S>
bool operator== (Point<S>, Point<S>);
template <typename T>
class Point {
// ...
friend bool operator==<T> (Point, Point);
};
References
http://web.mst.edu/~nmjxv3/articles/templates.html
The declaration of the operator==() is a template. The declaration made a friend is not a template but a non-template. To make the template operator==() a friend you need to make the friend declaration a template, too:
template <typename T> class Point;
template <typename S>
bool operator== (Point<S>, Point<S>);
template <typename T>
class Point {
// ...
template <typename S>
friend bool operator== (Point<S>, Point<S>);
};
This is a tricky issue: the friend declaration in the class will define a different friend function for each instantiation of your class. In other words, Point<int> and Point<double> will give rise to 2 different non-template friend functions. On the other hand, the outside function is a template function, not related to the friend inside the class. Solution: define the friend function inside the class. Due to friend name injection, it will be found successfully by ADL.
You have to put friend classes within each other, as well as in themselves. The Real one is named syntactically the same without replacing expressions. So friend bool operator==(P<T>,P<T>); goes in both of the classes. So put friend before bool in the class T :-)
Could you please advise why I am getting the error in the code below?
error: cannot define member function ‘Test<int>::Printer::Print’ within ‘Test<int>’
I am using gcc version 8.1.1 and compile the code as g++ -std=c++11.
Although, if I move the definition of function Print under the definition of struct Printer (i.e. making it inline implicitly), the compiler does not produce any error.
#include <iostream>
template <typename Type>
struct TestBase {
struct Printer {
template <typename T>
void Print(const T& t) {
std::cout << t << std::endl;
}
};
};
template <typename Type>
struct Test;
template<>
struct Test<int> : public TestBase<int> {
struct Printer : public TestBase<int>::Printer {
template <typename T>
void Print(int i, const T& t);
};
template <typename T>
void Printer::Print(int i, const T& t) {
std::cout << i << t << std::endl;
}
};
int main() {
Test<int> t;
}
UPDATE:
Brian pointed out the exact reason why it is the case: "... A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition..."
Brian not only answered the main question that started this topic but also an additional question that I asked in the comment to the accepted answer of him.
[class.mfct]/1, emphasis mine:
... A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition. ...
An enclosing class scope is thus not an allowed location for the definition.
This has been driving me crazy for the past couple hours, and I cannot seem to get around this problem. I have distilled the problem down to these 60 lines of code (including a main function).
#include <iostream>
namespace n1 {
// the general definition
template <class X, class Y> void f(X&, const Y&)
{
std::cout << "general template definition.\n";
}
} // namespace n1
namespace n2 {
// CRTP
template <class Derived> class A
{
int data;
// partial function template specialization for n1::f, and declare
// it a friend too, so that it may access the data attribute of A
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
}; // class A
} // namespace n2
namespace n1 {
// implementation for this particular function template specialization
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
{
std::cout << "partial template specialization: " << a.data << "\n";
}
} // namespace n1
namespace n2 {
// Another class!
class B : public A<B>
{
}; // class B
} // namespace n2
namespace n1 {
// --------------------
// tricky part is here!
// --------------------
template <class Y> void f(n2::B& b, const Y& y)
{
// FAIL! not a friend! How?
f(static_cast<n2::A<n2::B>&>(b), y);
}
} // namespace n1
int main()
{
n2::B b;
int x;
n1::f(b, x); // should print "partial template specialization"
return 0;
}
So, what I "want" is to have the compiler select my function template specialization of n1::f whenever it is invoked with a concrete subclass of A<Derived>. In order to make sure that the compiler favors my specialization, I need to supply, for every subclass (B in this case), also a template specialization for n1::f that simply delegates the call. When that happens, I expect the data member variable of A<Derived> to be accessible to n1::f, because I declare n1::f to be a friend of A<Derived>. However, GCC complains that A<Derived>::data is private and inaccessible, see this snippet on Coliru.
Is this construction possible? If so, how can I get around the compiler complaining that A<Derived>::data is not accessible? (Making it public is not an option).
Your class definition must look like this:
template <class Derived> class A
{
int data;
template <class D, class Y> friend void n1::f(A<D>& a, const Y& y);
};
In fact, function declaration is:
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
While your friend declaration is:
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
In this case, they are different beasts and that's why you receive that error. As you can see, template parameters lists are different. That's not a declaration of a function with a separated definition. They are two different function templates, one declared and the other one both declared and defined.
In other terms, in your code you are declaring a friend function but you never define it. On the other side, you introduced a free function template that cannot read the data member for it's private and the function isn't a friend one of A<Derived>.
See it running on wandbox.
everyone
I am a beginner of c++. Now I try to understand how compiler lookup a function with friend keyword.
The followings are the code with warning and error messages.
I have two problems in the code. One is warning and another is error.
At Problem(1), compiler warns that function including template parameter is non-template function. Why is it non-template function? And how can I define a function including template parameter as non-template function?
At Problem(2), friend template function, friendFunction(A const& val), is not looked up. In my understanding, it can be looked up by ADL method.
Please tell me how to understand the two problem above.
Thank you very much.
template<typename T>
class A {
/* ***** first declaration of functions without definition.
* ***** In this case, compiler assume the friend function will be defined
* ***** in one outer namespace, in this case ::. */
friend void friendFunction(A<T> const& val); // Problem(1) warning: please see below for message
// warning: friend declaration ‘void friendFunction(const A<T>&)’ declares a non-template function
};
// ??? How can I define friend void friendFunction(A<T> const& val) ???
template<typename T>
void friendFunction(A<T> const& val) {
std::cout << "::function(A<T>)" << std::endl;
}
void call_FriendFunction(A<int>* ptr);
void test_friend_keyword() {
A<int> a;
call_FriendFunction(&a);
}
void call_FriendFunction(A<int>* ptr) {
friendFunction(*ptr); // Problem(2) please see error message below
// undefined reference to `friendFunction(A<int> const&)'
/* In my understanding, the following friendFunction(*ptr); can be looked up
* by the following logic.
* (1) friendFunction(ptr) here is unqualified name.
* (2) Because friendFunction(*ptr) has an augment of A<int>* ptr,
* friendFunction(*ptr) have related class and related namespace of class A.
* (3) class A has declaration of
* friend void friendFunction(A<T> const& val);
* And it is allowed to see the friend template function.
* (4) As a result, friendFunction(*ptr) is looked up as
* friend void ::friendFunction(A<T> const& val); */
}
For the warning with
friend void friendFunction(A<T> const& val);
Assume that T in int, it declares
friend void friendFunction(A<int> const& val);
So you have to define
void friendFunction(A<int> const& val);
which is not the same as
template<typename T>
void friendFunction(A<int> const& val);
or even
template<>
void friendFunction<int>(A<int> const& val);
The possible fixes are to declare a template function friendFunction before:
template<typename T> class A;
template <typename T> void friendFunction(A<T> const& val);
template<typename T>
class A {
friend void friendFunction<>(A<T> const& val); // It is the template function
// Only the one with T is friend.
};
Live Demo
Or to provide definition inside the class:
template<typename T>
class A {
friend void friendFunction(A<T> const& val) // It is not template
{
/*Definition*/
}
};
Demo
I'm trying to create a template class with a friend function which is inside a nested namespace. It works fine if I remove all the namespaces or if I remove all the templatization. But with both in place it won't compile. Let's look at some code:
namespace MyNamespace
{
// Forward declaration
template <typename Type>
class Container;
// Forward declaration
namespace AccessPrivateImplementation
{
template <typename Type>
Type getValue(Container<Type>* container);
}
// Templatized class
template <typename Type>
class Container
{
friend Type AccessPrivateImplementation::getValue(Container<Type>* volume);
private:
Type value;
};
// Friend function inside a namespace
namespace AccessPrivateImplementation
{
template <typename Type>
Type getValue(Container<Type>* container)
{
return container->value;
}
}
}
int main(int argc, char* argv[])
{
MyNamespace::Container<int> cont;
MyNamespace::AccessPrivateImplementation::getValue(&cont);
return 0;
}
The compiler (VS2010) tells me:
error C2248: 'MyNamespace::Container::value' : cannot access private member declared in class 'MyNamespace::Container'
Does anyone have any idea what I'm missing?
The friend declaration inside the Container class template declares a friend non-template function getValue() that lives in the AccessPrivateImplementation namespace.
However, you haven't provided such a function. Instead, what you have in the AccessPrivateImplementation namespace is a function template, whose appropriate specialization you want to be friend of Container<T> (for a given T).
To achieve this, the declaration you need is:
friend Type AccessPrivateImplementation::getValue<>(Container<Type>* volume);
// ^^
Here is a live example that shows your code compiling with the above fix.
As per my comment, if you declare the friend like so it will work:
friend Type AccessPrivateImplementation::getValue<>(Container<Type>* volume);
^^