Defining static member of template class in a implementation file [duplicate] - c++

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 4 years ago.
I simplify the problem. I wanna know why this can't compile:
Error message: undefined reference to 'Foo<int>::j'
a.h
#pragma once
template<typename T>
class Foo{
public:
int bar(){
return j;
}
private:
static int j;
};
a.cpp
#include "a.h"
template<typename T>
int Foo<T>::j = 3;
main.cpp
#include "a.h"
#include <iostream>
using namespace std;
int main() {
Foo<int> f;
cout << f.bar();
return 0;
}

Templates are the cause.
template<typename T>
int Foo<T>::j = 3;
doesn't get resolved for main.cpp as it has no information about a.cpp.
And as for a.cpp it doesn't create Foo as it isn't used there.
For the system to work, you'd need to add
int Foo<int>::j = 3;
to a.cpp or
template<typename T>
int Foo<T>::j = 3;
to main.cpp.
On the side note, maybe new usage of inline keyword in C++17 i what you are looking for.

Related

Multiple definition gets solved with templates

a.hpp:
#pragma once
struct S
{
static int v;
};
int S::v = 0;
b.hpp:
#pragma once
void addOne();
b.cpp:
#include "b.hpp"
#include "a.hpp"
void addOne()
{
S::v += 1;
}
main.cpp:
#include <iostream>
#include "a.hpp"
#include "b.hpp"
int main()
{
S::v = 2;
addOne();
S::v += 2;
std::cout << S::v << std::endl;
}
Does not work when compiling with g++ -std=c++14 main.cpp b.cpp && ./a.out (multiple definition of S::v).
However when I change the code to:
a.hpp:
#pragma once
struct S
{
template<typename T>
static int v;
};
template<typename T>
int S::v = 0;
and replace all S::v with S::v<void> it compiles and works how I intended the first example to work (outputs 5).
I believe I know why the first code example does not work: The int S::v = 0; line gets once compiled in the main.cpp unit and once in the b.cpp unit. When the linker links these two together, then the variable S::v gets essentially redefined.(?)
Why does the code with the template work?
Why does the code with the template work?
Essentially, because the standard says so.
With templates, the rules usually amoun to: "everyone using them must have their definition available." The exact same applies to static data members of class templates: a definition of such a static data member must be present in every translation unit in which it is odr-used. It's up to the compiler & linker to make sure this does not lead to errors.
Note that since C++17, you can solve the non-template case by making the static data member inline:
#pragma once
struct S
{
static inline int v = 0;
};

Class Template Errors

The question asked is very different from the so called duplicate post as I have specific errors and they are just asking why it needs to be in the .h file... I already have it in the header file and am getting the errors below.
Updated the files and I still get the following errors.
1 Unresolved externals (lab12.exe line 1)
unresolved external symbol "public char__thiscall Pair::geetFirst(void)" (?getFirst#?$Pair#D##QAEDXZ) referenced in function_main (lab12.obj line 1)
Pair.h
#pragma once
template <class T>
class Pair
{
private:
T theFirst;
T theSecond;
public:
/*Pair(const T& dataOne, const T& dataTwo);*/
Pair(T a, T b) {
theFirst = a;
theSecond = b;
}
T getFirst();
T getSecond();
};
Pair.cpp
#include "stdafx.h"
#include "Pair.h"
template<class T>
T Pair<T>::getFirst()
{
return theFirst;
}
template<class T>
T Pair<T>::getSecond()
{
return theSecond;
}
Main.cpp
#include "stdafx.h"
#include "Pair.h"
#include <iostream>
using namespace std;
int main()
{
Pair <char> letters('a', 'd');
cout << letters.getFirst();
cout << endl;
system("Pause");
return 0;
}
You should put all code for template class Pair into the header file.
Also, there is no need to separate method declaration from definition in header.
'Pair T::Pair' is wrong because you do not need T here.

How to pass a struct to a class in c++? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I am new to c++ and this one has me stumped. I want to pass a struct to a class (I know they are technically the same) so the class can access the data in the struct. I don't mind if it is passed as a reference or a copy as there will be no changes to the struct within the class. Having said that a reference would probably be better for performance. I can get it all to work fine if I pass the members of the struct individually but the real version will have about 30 members so passing them individually isn't the best option.
My main cpp:
#include "stdafx.h"
#include "myClass.h"
#include <iostream>
using namespace std;
struct foo
{
int num;
double dbl;
};
int _tmain(int argc, _TCHAR* argv[])
{
foo bar;
bar.dbl=3.14;
bar.num=42;
baz qux(); //bar needs to be passed here
cout<<qux.getSum()<<endl;
return 0;
}
Class header:
using namespace std;
class baz
{
public:
baz(); //This is where type of bar (foo) is declared
void setSum(int, double);
double getSum();
private:
double sum;
};
Class cpp:
#include "stdafx.h"
#include "myClass.h"
#include <iostream>
using namespace std;
baz::baz() //this is where bar is called
{
setSum(bar.num, bar.dbl);
}
void baz::setSum(int num, double dbl)
{
sum=num*dbl;
}
double baz::getSum()
{
return sum;
}
So the nub of the question is, how do I get bar into baz?
Solved, put the struct definition into a separate header and included that where ever it was needed. Then just a simple change to the declaration in the class header and everything works perfectly. I have included the new code (minus the VS code for the benefit of Abyx who seems to find it so offensive) in case anyone else has the same problem.
Main cpp:
#include "myClass.h"
#include "foo.h"
#include <iostream>
using namespace std;
int main(int argc, _TCHAR* argv[])
{
foo bar;
bar.dbl=3.14;
bar.num=42;
baz qux(bar);
cout<<qux.getSum()<<endl;
return 0;
}
foo.h:
struct foo
{
int num;
double dbl;
};
myClass.h:
class baz
{
public:
baz(const struct foo&);
void setSum(int, double);
double getSum();
private:
double sum;
};
myClass.cpp:
#include "myClass.h"
#include "foo.h"
#include <iostream>
using namespace std;
baz::baz(const foo& blah)
{
setSum(blah.num, blah.dbl);
}
void baz::setSum(int num, double dbl)
{
sum=num*dbl;
}
double baz::getSum()
{
return sum;
}
Make additional constructor. Something like that:
baz::baz(const foo& st){
setSum(st);
}
void baz::setSum(const foo& st)
{
setSum(st.num, st.dbl);
}
then you can:
int _tmain(int argc, _TCHAR* argv[])
{
foo bar;
bar.dbl=3.14;
bar.num=42;
baz qux(bar); //bar needs to be passed here
cout<<qux.getSum()<<endl;
return 0;
}
Your main program:
#include "stdafx.h"
#include "myClass.h"
#include <iostream>
using namespace std;
struct foo
{
int num;
double dbl;
};
int _tmain(int argc, _TCHAR* argv[])
{
foo bar;
bar.dbl=3.14;
bar.num=42;
baz qux(); //bar needs to be passed here
cout<<qux.getSum()<<endl;
return 0;
}
Well, stdafx.h is a header that only makes sense if you turn on (or omit to turn off) use of Microsoft precompiled headers, which makes the Visual C++ preprocessor behave in decidedly non-standard ways. So better remove that. Also, _tmain is a Windows 9x support macro, that expands to either a standard main or a Microsoft-specific wmain. So ditch that also. Finally, there's no need for the return 0 at the end of a standard main, because that's the default return value of main. Also, what's that getSum? Do you write e.g. getsin or getcos? Better call it just sum. Then,
#include "myClass.h"
#include <iostream>
using namespace std;
struct foo
{
int num;
double dbl;
};
int main()
{
foo bar;
bar.dbl=3.14;
bar.num=42;
baz qux( bar ); // See how easy it is to pass `bar`
cout<<qux.sum()<<endl;
}
For the baz class header file, DO NOT EVER have using namespace std in the global namespace in a header file. I.e. remove that also. Then,
#pragma once
#include -- relevant header --
class baz
{
private:
double sum_;
public:
baz( foo const& blah ): sum_( blah.whatever + something ) {}
void setSum( int const n, double const v ) { sum_ = n*v; }
double sum() const { return sum_; }
};
Note: #pragma once is a de facto standard, but it's not ISO standard.

Undefined reference from templated function (C++) [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 10 years ago.
main.o: In function `main':
main.cpp:(.text+0x2f): undefined reference to `Foo<int>::display(int)'
collect2: ld returned 1 exit status
caused by
g++ -c *.cpp && g++ *.o -o foo
with foo.hpp:
#ifndef FOO_H_
#define FOO_H_
template<typename T>
class Foo {
private:
T ft_;
public:
Foo(const T & ft) : ft_(ft) { }
Foo display(T x);
};
#endif
foo.cpp:
#include "foo.hpp"
#include<iostream>
using namespace std;
template<typename T>
Foo<T> Foo<T>::display(T x) {
// do some stuff - not too relevant
cout << "[" << x << "]";
Foo<T> res(x);
return res;
}
and main.cpp:
#include<iostream>
#include "foo.hpp"
using namespace std;
int main() {
Foo<int> f(42);
Foo<int> g = f.display(39);
return 0;
}
Why?!
P. S. Works with inlined function definitions. Troubles come whenever declaration and definition of a function is split into two files...
In C++ you need to put the definition of templated methods and functions into the header file.

C++ Template error [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Undefined reference error for template method
Hello I have this code that is giving me this error:
undefined reference to `MyStack::push(int)' main.cpp
Why??
MyStack.h:
#ifndef STACK_H
#define STACK_H
template <typename T>
class MyStack
{
private:
T *stack_array;
int count;
public:
void push(T x);
void pop(T x);
void xd(){}
};
#endif /* STACK_H */
MyStack.cpp:
#include "mystack.h"
template <typename T>
void MyStack<T>::push(T x)
{
T *temp;
temp = new T[count];
for(int i=0; i<count; i++)
temp[i] = stack_array[i];
count++;
delete stack_array;
stack_array = new T[count];
for(int i=0; i<count-1; i++)
stack_array[i] = temp[i];
stack_array[count-1] = x;
}
template <typename T>
void MyStack<T>::pop(T x)
{
}
main.cpp:
#include <iostream>
#include "mystack.h"
using namespace std;
int main(int argc, char *argv[])
{
MyStack<int> s;
s.push(1);
return 0;
}
The definition of the members of the class template must be in the same file, but you've defined them in a different file (MyStack.cpp).
The simple solution is that add the following line to your MyStack.h file at the end:
#include "MyStack.cpp" // at the end of the file
I know that is .cpp file, but that will solve your problem.
That is, your MyStack.h should look like this:
#ifndef STACK_H
#define STACK_H
template <typename T>
class MyStack
{
private:
T *stack_array;
int count;
public:
void push(T x);
void pop(T x);
void xd(){}
};
#include "MyStack.cpp" // at the end of the file
#endif /* STACK_H */
If you do so, then #include "mystack.h" is not needed in MyStack.cpp anymore. You can remove that.
See C++ FAQ-35.12
You have to place your template class declaration and implementation inside header file because compiler needs to know about template implementation when instantiating template while compiling. Try to put implementation of MyStack inside MyStack.h
You can find more detailed explanation here. Just move to the "Templates and multiple-file projects" at the bootom of the article.