Redefinition error when defining friend function inside class template [duplicate] - c++

This question already has an answer here:
A template friend function inside a template class
(1 answer)
Closed last year.
I am learning friend declarations in C++ using the books listed here. So after reading, to test my understanding of the concept, i wrote the following program whose output i am unable to understand:
template<typename T>
struct Name
{
friend void anotherFeed(int x)//anotherFeed is implicitly inline and its definition is generate only when we use this nonmember function so why are we getting error at instiantiation?
{
}
};
int main()
{
Name<int> s;
Name<double> p;//error here. My question is that this is instiantiation of the class template Name<double> and not a call to anotherFeed so why do we get error here?
}
The above program give the following error:
error: redefinition of ‘void anotherFeed(int)’
This is my current understanding:
The friend non-member function anotherFeed(int) is implicitly inline.
Even if anotherFeed(int) is inline, we cannot define the same function(doesn't matter inline or not) in the same translation unit.
The definition of anotherFeed(int) is generated only when we use/call this function just like for a nontemplate member function of a class template.
My question is that: Assuming that my understanding(the above 3 points) are correct, since i have not called/used anotherFeed so its definition should not be generated and we should not get the redefinition error at the time of creating an instance of the class template. Only when we call anotherFeed using those instances, we should get the redefinition error. So why do we get error at the time of creating class template's instance. Is there anything wrong in any of the above 3 points.
Summary
I read that the definitions for these functions(non template member functions and friend non template functions) are instantiated only when used. That is,
Name<int> s;
Name<double> p; //this should work in principle because this does not instantiate the definition of anotherFeed(int)
But this doesn't happen. Why/How?

The free function
friend void anotherFeed(int x){}
is not dependent on the template parameter, hence, there is only this one free function which is defined twice in your example. Make it a forward declaration only
template<typename T>
struct Name {
friend void anotherFeed(int x);
};
and define it outside the class definition
void anotherFeed(int x) {}
and all's well.

For a function template, its declaration can be instantiated without instantiating its definition.
This instantiates everything except the function body (more or less).
The declaration of your function is instantiated when the class is instantiated. When (and if) you actually call the function, its definition is instantiated.
I can't find the right standard quote, but apparently the compiler doesn't need to instantiate the definitions to reject the duplicate instantiated declarations.

This issue is addressed here.
However, for the purpose of determining whether an instantiated redeclaration is valid according to [basic.def.odr] and [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition.
So even though there is no actual instantiation of the definition of anotherFeed(int) in your program, the compiler is still required to diagnose multiple definitions within the same translation unit as if the definition had been instantiated every time the declaration were instantiated.
And so when you wrote:
Name<double> p; //instantiate a declaration of anotherFeed(int) for the second time.
The above statement, instantiate a redeclaration of anotherFeed(int) and since this declaration corresponds to a definition, according to the quoted statement at the beginning of my answer you get the redefinition error.

Related

Checking whether a class template has been instantiated?

Is there an easy way to see whether a class has been instantiated in a translation unit? An exercise from C++ Primer asks for each labelled statement, whether an instantiation happens:
template <typename T> class Stack { };
void f1(Stack<char>); // (a)
class Exercise {
Stack<double> &rsd; // (b)
Stack<int> si; // (c)
};
int main() {
Stack<char> *sc; // (d)
f1(*sc); // (e)
int iObj = sizeof(Stack< string >); // (f)
}
I'm not sure how I could actually check my answers for these. I thought maybe I could use explicit instantiations for each class type (e.g. extern template class Stack<char>) and then never have a corresponding explicit instantiation definition in the program. That way if something was instantiated, if the definition didn't later appear then the linker would kick up an error.
However the compiler/linker doesn't always recognise such an error:
template <typename T> class A{ };
extern template class A<int>;
int main(){
A<int> a;
}
This compiles fine on gcc 4.9.2. However if this was the only object file in my program is should be an error as far as I can tell from [14.7.2][11] of N3337:
If an entity is the subject of both an explicit instantiation declaration and an explicit instantiation definition in the same translation unit, the definition shall follow the declaration. An entity that is the subject of
an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation (14.7.1) in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required.
(I'm guessing the "no diagnostic required" is why this doesn't kick up an error?). Alternatively is it the case that instantiations happen whenever an incomplete class type isn't viable for an expression - so that I could check by removing the definition of Stack?
template <typename T> class Stack;
So that each incomplete type error corresponds to a place where an instantiation would have occured?
You can use the nm tool on the executable. This will show what file contains function definitions. Also gcc provides a flag to strip out unused functions when doing the link.
Compile with “-fdata-sections” to keep the data in separate data sections and “-ffunction-sections” to keep functions in separate sections, so they (data and functions) can be discarded if unused.
Link with “–gc-sections” to remove unused sections.

Template class's static variable initialization, c++

consider the following code:
//header.h
template<class T>
class A
{
static int x;
};
template<class T>
int A<T>::x = 0;
//source1.cpp
#include "header.h"
void f(){} // dummy function
//main.cpp
#include "header.h"
int main(){}
In this case code compiles perfectly without errors, but if I remove the template qualifier from class
class A
{
static int x;
};
int A::x = 0;
In this case compiler erred with multiple definition of x. Can anybody explain this behavior?
And when the template class's static variable is initialized / instantiated??
Compiler will remove duplicate template instantiations on its own. If you turn your template class into regular one, then its your duty to make sure only one definition of static variable exists (otherwise linker error will appear). Also remember that static data members are not shared between instatiations of templates for different types. With c++11 you can control instatiations on your own using extern templates: using extern template (C++11).
As for the point of instatiation for static members:
14.6.4.1 Point of instantiation [temp.point]
1 For a function template specialization, a member function template specialization, or a specialization for a
member function or static data member of a class template, if the specialization is implicitly instantiated
because it is referenced from within another template specialization and the context from which it is referenced
depends on a template parameter, the point of instantiation of the specialization is the point of
instantiation of the enclosing specialization. Otherwise, the point of instantiation for such a specialization
immediately follows the namespace scope declaration or definition that refers to the specialization.
so point of instatiation should be ie. right after main() if you use your type for the first time inside main().
Templates as the name suggest are the the fragments of code that will be used several times for different parameters. For templates the compiler is to ensure if their methods and static fiels definition are linked only ones. So if you create a static field with its default value the compiler is obliged to provide single memory cell (for the same template parameter set) even though the template class header is included several times. Unfortunetly non-template classes you need to be managed by yourself.
As for the second question, I believe the standard does not state when the static fields need to be initialized, each compiler can implement then it in its own manner.
It is necessary to instantiate/initialize static members in cpp files not in headers. Static members are property of class not property of objects, so if you include header file in more cpp files, it looks like you are initializing it more times.
Answer to this question is more complex. Template is not one class. It is instantiating on demand. It means that every different use of template is one standalone "template instance". For example if you use A<int> and A<float> than you will have 2 different classes therefore you would need to initialize A<int>::x and A<float>::x.
For more info see this answer: https://stackoverflow.com/a/607335/1280316
A class (be it a template or not) can (and should) be declared in any compilation unit that referes to it.
A static field initialization does defines a variable, and as such it should exist only in one compilation unit -> that's the reason why you get an error when class A is not a template.
But when you declare a template, nothing is really created untill you instantiate it. As you never instantiate the template, the static field is never defined and you get no error.
If you had two different instantiations in source1.cpp (say A<B>) and main.cpp (say A<C>) all will still be fine : you would get A<B>::x in source1 and A<C>::x in main => two different variables since A<B> and A<C> are different classes.
The case where you instantiate same class in different compilation units is trickier. It should generate an error, but if it did, you could hardly declare special fields in templates. So it is processed as a special case by the compiler as it is explained in this other answer to generate no errors.

C++ - Define member function outside template-class but in header

I have defined a simple class-template with one member function. It is defined outside the class with an additional (explicit) specialization, also defined outside the class. All in one headerfile. If you include this header in multiple translation units you get a linker error due to One-Definition-Rule.
// Header with a template
template <class T>
class TestClass
{
public:
TestClass() {};
~TestClass() {};
bool MemberFunction();
};
template <class T>
bool TestClass<T>::MemberFunction()
{
return true;
}
template <>
bool TestClass<double>::MemberFunction()
{
return true;
};
Everything fine so far. But If I put the definition of the member function inside the class body, the linker error disappears and the functions can be used throughout different translation units.
// Header with a template
template <class T>
class TestClass
{
public:
TestClass() {};
~TestClass() {};
bool MemberFunction()
{
return true;
}
};
template <>
bool TestClass<double>::MemberFunction()
{
return true;
};
My question is why does it work that way? I use MSVC 2012. ODR has some exceptions on templates what I first thought to be the reason. But the definition of the "Base" function inside/outside the class makes the difference here.
14.7/5 says
5 For a given template and a given set of template-arguments,
an explicit instantiation definition shall appear at most once in a program,
an explicit specialization shall be defined at most once in a program (according to 3.2), and
both an explicit instantiation and a declaration of an explicit specialization shall not appear in a program unless the explicit
instantiation follows a declaration of the explicit specialization.
An
implementation is not required to diagnose a violation of this rule.
The second bullet applies to your case. The ODR defined in 3.2 says the same thing, albeit in a less distilled form.
Regardless of where and how the non-specialized version of member function is defined, the specialized version definition
template <> bool TestClass<double>::MemberFunction()
{
return true;
};
has to go into a .cpp file. If kept in the header file, it will produce an ODR violation once the header gets included into more than one translation unit. GCC reliably detect this violation. MSVC seems to be less reliable in that regard. But, as the quote above states, an implementation is not required to diagnose a violation of this rule.
The header file should only contain a non-defining declaration of that specialization
template <> bool TestClass<double>::MemberFunction();
The fact that in MSVC the error appears or disappears depending on such seemingly unrelated factor as how the non-specialized version of the function is defined must be a quirk of MSVC compiler.
After further research, it appears that MSVC implementation is actually broken: its behavior goes beyond what's allowed by the "no diagnostic is required" permission given by the language specification.
The behavior you observed in your experiments in consistent with the following: declaring the primary function template as inline automatically makes the explicit specialization of that template inline as well. This is not supposed to be that way. In 14.7.3/14 the language specification says
An explicit specialization of a function template is inline only if it
is declared with the inline specifier or defined as deleted, and
independently of whether its function template is inline.

Function specialization: Which is the declaration?

Given:
template<class T>
struct test {
void foo(int b);
void testFunc( int a )
{
}
};
void test::foo(int b)
{
}
template<>
void test<float>::testFunc( int a )
{
}
void someFunction()
{
}
We know that "test::foo" has a declaration in the test class, and a definition outside the class definition.
We also know that "someFunction" has a declaration which is also its definition.
In like manner "test::testFunc" (non-specialized), has a declaration which is also its definition.
Is the specialization function "test<float>::testFunc" said to be declared with the declaration of "testFunc" inside of class "test" and defined separately, or is its declaration also the definition?
The explicit specialization in your example is a declaration that is also a definition. You could also declare it separately:
template<>
void test<float>::testFunc( int a );
and if the function was used, the linker would expect it to be defined somewhere.
The declaration inside the class is the declaration and definition of the member function template.
BTW, foo should be defined like this:
template <class T>
void test<T>::foo(int b)
{
}
I would like to add to the useful answer #Vaughn provided.
In the template definition of test, you have a non-defining member function declaration and also a defining member function declaration. But that function definition and declaration is associated with the surrounding template test<T>, and not with the class test<float> that will eventually be instantiated from it!
If you implicitly instantiate test<float> from that template, for example by using the ::-operator (scope) on it, or by creating a variable definition having that type and so on, then declarations but not necessarily the definitions of all members are also implicitly instantiated. All of them are associated with and members of test<float>.
So when you write your explicit specialization for test<float>::testFunc, because you used :: to look into the class test<float>, that class is being implicitly instantiated and with it all its member declarations.
The definition of test<float>::testFunc is only instantiated when it is required (for example when you call it).
The explicit specialization you declared then redeclares the member function that was previously implicitly instantiated and provides a definition that is associated with test<float>. It is a real function and cannot be safely defined in a header unless it is marked inline - otherwise you risk "defined more than once" errors when you include its header multiple timrs.
To summarize what declarations and definitions exist for testFunc and where they come from:
By your template definition:
test<T>::testFunc(int);
test<T>::testFunc(int) { }
Generated specialization by the compiler from test<T>::testFunc(int);
test<float>::testFunc(int);
Explicit specialization by you of test<T>::testFunc(int);
test<float>::testFunc(int);
test<float>::testFunc(int) { }
In particular, there is no generated definition of test<float>::testFunc. If there was, then your code would be ill-formed, without diagnostics required, because the generated definition would interfere with your explicit specialization that provided a definition for the same function. But such a thing can only happen if you cause its instantiation before explicitly specializing it. So if you move the explicit specialization definition into a .cpp file (if you don't want to make it inline), put an explicit specialization declaration, like #Vaughn demonstrated, into the header.

forward declaration and template function error

Currently I have a frustrating problem with forward declaration and template function. I have been trying to googling and do some modification but nothing has worked so far. Below is the snippet of the code:
class TaskScheduler; --> //forward declaration of ‘struct TaskScheduler’
//
//
class TaskEvent {
//
//
};
class HostTask {
//
//
};
template<class T> inline HostTask*
findT(TaskScheduler* tss, T* e)
{
map<int, HostTask*>::iterator it;
bool bEq = false;
for(it = tss->tasks_.begin(); it != tss->tasks_.end(); it++) { --> //error: invalid use of incomplete type ‘struct TaskScheduler’
if(dynamic_cast<TaskEvent*>(e))
bEq = dynamic_cast<TaskEvent*>(e)->equal(it->second->ev_);
else if(dynamic_cast<HostTask*>(e))
bEq = dynamic_cast<HostTask*>(e)->equal(it->second);
if(bEq) {
return it->second;
}
}
return NULL;
}
//
//class TaskScheduler definition
class TaskScheduler : virtual public HCIEventsHandler {
friend HostTask* findT<TaskEvent>(TaskScheduler* tss, TaskEvent* e); //findT function is used here
//
//
};
Here is the error message that I've got which is shown in the code as well:
./bt-taskscheduler.h:159: error: forward declaration of ‘struct TaskScheduler’
./bt-taskscheduler.h:229: error: invalid use of incomplete type ‘struct TaskScheduler’
Could anybody show me what is going wrong in this code? Any help is appreciated..
In the definition of findT you are using tss->tasks_ which dereferences a pointer to an object of type TaskScheduler so you need a full definition of the struct, not just a forward declaration visible at this point in the program.
The definition of struct TaskScheduler needs to appear before the definition of the findT function template.
You are using the TaskScheduler class in your for-loop header "tss->tasks_.begin()". Compiler does not know, whether this class have "tasks_" member or not.
It is not the problem with your templates, any function, inlined in the header file will cause the same error. Forward declaration of the class only allows you to declare pointers (or references) to that class or pass this class objects as a parameters. You cannot "use" the class (call its methods or get the member data), until you fully define your class.
Because you use the definition of TaskScheduler in the findT functions, you have two options:
Move the definition of TaskScheduler above the findT template function
Make TaskScheduler a second template of of the findT function
Like this:
template< class U, class T>
inline HostTask* findT( U* tss, T* e)
{
//...
}
Next to trouble with the forward declaration, it looks as if your findT function should actually be a member function of the scheduler class: it makes extensive use of the scheduler's data members.
These members are private, so you need a way to publish them, and fall back onto the friend declaration.
So either you make the members public, or, better, you refactor the findT function into a member function.
There's no problem in making it a templated member function, either. And you will automatically get rid of the friend declaration.
//class TaskScheduler definition
class TaskScheduler : virtual public HCIEventsHandler {
public:
template<class T> inline HostTask* findT(T* e) const
{
map<int, HostTask*>::iterator it;
bool bEq = false;
for(it = tasks_.begin(); it != tasks_.end(); it++) {
if(dynamic_cast<TaskEvent*>(e))
bEq = dynamic_cast<TaskEvent*>(e)->equal(it->second->ev_);
else if(dynamic_cast<HostTask*>(e))
bEq = dynamic_cast<HostTask*>(e)->equal(it->second);
if(bEq) {
return it->second;
}
}
return NULL;
}
};
As other posters have mentioned, you are dereferencing a pointer to TaskScheduler without a definition of the type, which will cause an error just as it would in any definition.
What you are probably confused about is that your code likely works on some compilers, even modern ones (I know MSVC is incorrect in this regard, but I do not know if it will accept the above code*). These compilers do not properly implement what is known as two-phase name lookup.
Two-phase name loopkup is a more predictable method of name lookup used in templates than the simpler form used by some compilers. In the simpler form, the template definition is parsed and stored for use only when it's instantiated, and name lookup is performed on all names in the template from the point at which you instantiate the template. With two-phase name lookup, names used within a template are sorted into dependent names and non-dependent names. Non-dependent names are names that the compiler can resolve immediately - any name that doesn't rely on a template parameter, directly or indirectly. These names are processed immediately when you define the template. Dependent names, on the other hand, cannot be resolved immediately; they are stored and then, when instantiation is performed, looked up in the template's context, but also in the context in which the template was instantiated for argument-dependent lookup only.
Here's an example:
void foo (int);
template <typename T> void bar(T t) {
foo(1.0);
foo(t);
}
void foo (double);
struct qux {};
void foo (qux);
void baz () {
bar (1.0);
qux q;
bar (q);
}
N.B. I know I got the metasyntactic names in the wrong order. I apologize, but I added qux last and couldn't be bothered to rewrite my comment.
The instantiations of the bar template each call foo twice. The first call is non-dependent, so the compiler resolves it as soon as it sees it. The result is that it calls foo (int), applying a conversion, even though it will later find a better definition. This is no different from any other function call in C++. The tricky bit comes with the second call, which is dependent. The first call in baz calls bar<double>, the latter calls bar<qux>. The instantiated bar attempts to call foo with an object of type T. In the double scenario, since primitives never use argument-depedent lookup, the result is once again looked up only from bar, and foo(int) is found. When called with qux, however, argument-dependent lookup is applied both in the the definition and instantiation context**, so foo(qux) is called.
It can be a tad stupid, but it tends to Do The Right Thing. Also, I hope you actually understood that; it can be rather confusing. You'll need to read that Wikipedia link to understand fully.
* MSVC may implement a lesser form of two-phase name lookup where it does resolve non-dependent names correctly, but it takes into account definitions after the template for dependent names. I forget whether it does this or omits two-phase lookup entirely and I don't have a copy of the program to check.
** In nearly every case, the instantiation context includes every declaration the definition context does. There is, however, the export keyword which can cause this not to be the case. That keyword is only implemented in one compiler frontend - I wonder why nobody else has implemented it? [/sarcasm]