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
Related
Why am I getting an error message when calling unary + with operator syntax? If I call it with function syntax, it is OK. Live demo.
template <int size>
struct Buffer { char buf[size]; };
template <class T>
struct Wrapper { void operator+() {} };
Wrapper<Buffer<-5>> a;
void f1() { +a; } // error: Buffer<-5>::buf has negative size
void f2() { a.operator+(); } // OK
The unqualified lookup invokes ADL, which needs to know if there are any friend functions defined in the associated classes. Buffer<-5> is one such, so it is instantiated. The fact that it’s syntactically obvious that it declares no friends doesn’t change the fact that the check for same involves completing the class type, which fails.
As an example let's put Buffer into namespace N, and operator+ into Buffer. If a's type is Wrapper<N::Buffer<5>> (5 rarher than -5), operator+ is found by ADL, and the code compiles (live demo):
template <class T>
struct Wrapper {};
namespace N {
template <int size>
struct Buffer {
template <class T> friend void operator+(const Wrapper<T>&) {}
char buf[size];
};
}
Wrapper<N::Buffer<5>> a;
void f1() { return +a; }
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.
OK I have:
template<typename T>
class Reader
{
class Input
{
template<typename C>
void operator()(C& val) const
{
/* Do Some Work */
}
};
};
Unfortunately the generic version of "Do Some Work" does not work for me. Nor it is easy to modify because it is in the middle of some heavy template meta programming code.
So I though I could specialize the method for my type. So my first step was to try and pull the general method out of the class.
template<typename T>
class Reader
{
class Input
{
template<typename C>
void operator()(C& val) const;
};
};
template<typename T>
template<typename C>
void typename Reader<T>::Input template operator()<C>(C& val) const // LINE 13
{
/* Do Some Work */
}
Unfortunately I am getting the error:
s.h:13: error: error: expected ‘)’ before ‘&’ token
Just write it like normal
template<typename T>
template<typename C>
void Reader<T>::Input::operator()(C& val) const // LINE 13
{
/* Do Some Work */
}
Defining the generic version out of class doesn't help you with providing special versions of it though, or I do miss the goal of yours here.
I guess it is impossible as it counts as partial function template specialization, which is not allowed. void Reader<T>::Input::operator () (C& int) has an implicit first argument (the this pointer) of type Reader<T>::Input *, hence its signature is in fact void (Reader<T>::Input *, C &). You are trying to specify C, yet not T.
template <typename T> class Foo;
template <typename T> int g(Foo<T> const&);
template <typename T> class Foo
{
public:
template <typename U> int f(Foo<U> const& p) const { return p.m; }
// which friend declaration will allow the above function to compile? The
// next one doesn't work.
template <typename U> friend void Foo<U>::template f<T>(Foo<T> const&) const;
// while this one work for g().
friend int g<T>(Foo<T> const&);
private:
int m;
};
template <typename T> int g(Foo<T> const& p) { return p.m; }
// Let's call them
void bar()
{
Foo<int> fi;
Foo<double> fd;
fd.f(fi);
g(fi);
}
The above doesn't compile with g++ nor Como. g() is here to show what I would like to do with f().
For instance, here are g++ messages:
foo.cpp:11: error: invalid use of template-id ‘f<T>’ in declaration of primary template
foo.cpp: In member function ‘int Foo<T>::f(const Foo<U>&) const [with U = int, T = double]’:
foo.cpp:27: instantiated from here
foo.cpp:17: error: ‘int Foo<int>::m’ is private
foo.cpp:7: error: within this context
and como's one:
"ComeauTest.c", line 11: error: an explicit template argument list is not allowed on
this declaration
template <typename U> friend void Foo<U>::template f<T>(Foo<T> const&) const;
^
"ComeauTest.c", line 7: error: member "Foo<T>::m [with T=int]" (declared at line 17)
is inaccessible
template <typename U> int f(Foo<U> const& p) const { return p.m; }
^
detected during instantiation of "int Foo<T>::f(const Foo<U> &)
const [with T=double, U=int]" at line 27
2 errors detected in the compilation of "ComeauTest.c".
Variants suggested by the error messages didn't either.
BTW, I know of the obvious work around
template <typename U> friend class Foo<U>;
Edit:
14.5.4/5 (of n3225, 14.5.3/6 of C++98 is similar but the following text is clearer in n3225) starts by
A member of a class template may be declared friend of a non-template class...
which could imply that a member of a class template may not be declared friend of a template class but my first interpretation would that this sentence was an introduction for the following explanations (mainly they apply to any specialisation, explicit or not, given that the prototype is correct).
I think you have to say template <> before the friend declaration so it knows you're friending a specialization.
EDIT: I can't get any error with your code, even making an instantiation and calling g. Can you post a minimal set of actual code that's causing the error, along with the error message?
Though I'm not 100% sure this is strictly standard conforming,
the following code can be compiled by ideone(gcc-4.3.4) and Comeau online:
template< class >
class Foo {
int m;
public:
template< class U > int f( Foo<U> const& p ) const { return p.m; }
template< class U > template< class V >
friend int Foo<U>::f( Foo<V> const& ) const;
};
void bar() {
Foo<int> fi;
Foo<double> fd;
fd.f( fi );
}
Hope this helps.
i try to design a template for my university project. i wrote the follwing code:
#ifndef _LinkedList_H_
#define _LinkedList_H_
#include "Link.h"
#include <ostream>
template <class L>//error one
class LinkedList
{
private:
Link<L> *pm_head;
Link<L> * pm_tail;
int m_numOfElements;
Link<L>* FindLink(L * dataToFind);
public:
LinkedList();
~LinkedList();
int GetNumOfElements(){return m_numOfElements;}
bool Add( L * data);
L *FindData(L * data);
template <class L> friend ostream & operator<<(ostream& os,const LinkedList<L> listToprint);//error two
L* GetDataOnTop();
bool RemoveFromHead();
L* Remove(L * toRemove);
this templete uses the link class templete
#ifndef _Link_H_
#define _Link_H_
template <class T>//error 3
class Link
{
private:
T* m_data;
Link* m_next;
Link* m_prev;
public:
Link(T* data);
~Link(void);
bool Link::operator ==(const Link& other)const;
/*getters*/
Link* GetNext()const {return m_next;}
Link* GetPrev()const {return m_prev;}
T* GetData()const {return m_data;}
//setters
void SetNext(Link* next) {m_next = next;}
void SetPrev(Link* prev) {m_prev = prev;}
void SetData(T* data) {m_data = data;}
};
error one: shadows template parm `class L'
error two:declaration of `class L'
error three: shadows template parm `class T'
i dont understand what is the problem. i can really use your help
thank you :)
These error messages really belong together:
a.cc:41: error: declaration of ‘class L’
a.cc:26: error: shadows template parm ‘class L’
This means that in line 41, you introduce a template parameter L; in my copy, this refers to
template <class L> friend ostream & operator<<(ostream& os,
const LinkedList<L> listToprint);//error two
And that declaration shadows the template parameter in line 26:
template <class L>//error one
class LinkedList
You need to rename the template parameter in the friend declaration.
Edit: The relevant language specification is 14.6.1/7
A template-parameter shall not be
redeclared within its scope (including
nested scopes). A template-parameter
shall not have the same name as the
template name.
When you refer to L in const LinkedList<L> listToprint, it's not clear whether you mean the L of the friend or the L of the class. So write
template <class L1> friend ostream & operator<<(ostream& os,
const LinkedList<L1> listToprint);
Just remove the
template <class L>
from the friend member function declaration.
You also need to replace uses of ostream with std::ostream unless you have a using namespace std somewhere in your code.
Otherwise, the code looks fine.