This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 7 years ago.
I have a static array inside a class template. The linker complains about a undefined symbol and even after applying the tips I saw on the web, I can't figure out what goes wrong.
Header
template<unsigned int N1, unsigned int N2>
class Foo
{
private:
static const int Size = N1 * N2;
public:
// stuff
private:
static float mArray[Size];
}
CPP
template <unsigned int N1, unsigned int N2>
float Foo<N1, N2>::mArray[size] = {0};
The linker complains about Foo<...>::mArray not being defined. I got it to compile (and link) when I move the definition to the header but I know that this is bad practice for statics. What is the best approach here?
Cheers
As with nearly everything else template-y, the definition of the static data member of a class template needs to be accessible in all translation units using it—in other words, put it in the header file. The compiler+linker are required to make this work without multiple-definition errors.
Related
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Static member initialization in a class template
(3 answers)
Closed 4 years ago.
Let's say for some reason, I want to have a class template MyTemp with some static data member smDummyVar :
Mytemp.h
#ifndef MY_TEMP_H
#define MY_TEMP_H
template<class T>
class MyTemp{
...
private:
static int smDummyVar;
...
};
#include "MyTemp.cpp"
#endif //MY_TEMP_H
Mytemp.cpp
...
template<class T> int MyTemp<T>::smDummyVar = 0;
...
Since the compiler requires that the definition and declaration of a template be at the same place, so I include MyTemp.cpp in MyTemp.h .
Now: I want to use MyTemp at many places and create objects using the template:
case1.cpp
#include "MyTemp.h"
void dummyfunc1(){
MyTemp<int> myTemp1;
}
case2.cpp
#include "MyTemp.h"
void dummyfunc2(){
MyTemp<int> myTemp2;
}
I won't get any error from the compiler, but I'd get warning from the linker:
"multiple definition for MyTemp<int>::smDummyVar" ... defined in invalid_group(case1.o) ... rejected in favour of symbol defined in ...(case2.o)
Question: how can I get rid of this warning ?
Thanks a lot in advance for your help !
====================================
inspired by one of the answers in this thread Why can templates only be implemented in the header file?
I found the following solution:
i. remove #include "MyTemp.cpp" in MyTemp.h
ii. specialized.h
#include "MyTemp.h"
typedef MyTemp<int> MySpecialized;
iii. specialized.cpp
#include "MyTemp.cpp"
template class MyTemp<int>;
iv. give specialized.cpp to cmake file
v. include specilized.h in case1.cpp and case2.cpp
the "multiple definition" warning issued by the linker will go away.
Thank you guys for helping !
Very simply put:
I have a class that consists mostly of static public members, so I can group similar functions together that still have to be called from other classes/functions.
Anyway, I have defined two static unsigned char variables in my class public scope, when I try to modify these values in the same class' constructor, I am getting an "unresolved external symbol" error at compilation.
class test
{
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
test::test()
{
X = 1;
Y = 2;
}
I'm new to C++ so go easy on me. Why can't I do this?
If you are using C++ 17 you can just use the inline specifier (see https://stackoverflow.com/a/11711082/55721)
If using older versions of the C++ standard, you must add the definitions to match your declarations of X and Y
unsigned char test::X;
unsigned char test::Y;
somewhere. You might want to also initialize a static member
unsigned char test::X = 4;
and again, you do that in the definition (usually in a CXX file) not in the declaration (which is often in a .H file)
Static data members declarations in the class declaration are not definition of them.
To define them you should do this in the .CPP file to avoid duplicated symbols.
The only data you can declare and define is integral static constants.
(Values of enums can be used as constant values as well)
You might want to rewrite your code as:
class test {
public:
const static unsigned char X = 1;
const static unsigned char Y = 2;
...
test();
};
test::test() {
}
If you want to have ability to modify you static variables (in other words when it is inappropriate to declare them as const), you can separate you code between .H and .CPP in the following way:
.H :
class test {
public:
static unsigned char X;
static unsigned char Y;
...
test();
};
.CPP :
unsigned char test::X = 1;
unsigned char test::Y = 2;
test::test()
{
// constructor is empty.
// We don't initialize static data member here,
// because static data initialization will happen on every constructor call.
}
in my case, I declared one static variable in .h file, like
//myClass.h
class myClass
{
static int m_nMyVar;
static void myFunc();
}
and in myClass.cpp, I tried to use this m_nMyVar. It got LINK error like:
error LNK2001: unresolved external symbol "public: static class...
The link error related cpp file looks like:
//myClass.cpp
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
So I add below code on the top of myClass.cpp
//myClass.cpp
int myClass::m_nMyVar; //it seems redefine m_nMyVar, but it works well
void myClass::myFunc()
{
myClass::m_nMyVar = 123; //I tried to use this m_nMyVar here and got link error
}
then LNK2001 is gone.
Since this is the first SO thread that seemed to come up for me when searching for "unresolved externals with static const members" in general, I'll leave another hint to solve one problem with unresolved externals here:
For me, the thing that I forgot was to mark my class definition __declspec(dllexport), and when called from another class (outside that class's dll's boundaries), I of course got the my unresolved external error.
Still, easy to forget when you're changing an internal helper class to a one accessible from elsewhere, so if you're working in a dynamically linked project, you might as well check that, too.
When we declare a static variable in a class, it is shared by all the objects of that class. As static variables are initialized only once they are never initialized by a constructor. Instead, the static variable should be explicitly initialized outside the class only once using the scope resolution operator (::).
In the below example, static variable counter is a member of the class Demo. Note how it is initialized explicitly outside the class with the initial value = 0.
#include <iostream>
#include <string>
using namespace std;
class Demo{
int var;
static int counter;
public:
Demo(int var):var(var){
cout<<"Counter = "<<counter<<endl;
counter++;
}
};
int Demo::counter = 0; //static variable initialisation
int main()
{
Demo d(2), d1(10),d3(1);
}
Output:
Count = 0
Count = 1
Count = 2
In my case, I was using wrong linking.
It was managed c++ (cli) but with native exporting. I have added to linker -> input -> assembly link resource the dll of the library from which the function is exported. But native c++ linking requires .lib file to "see" implementations in cpp correctly, so for me helped to add the .lib file to linker -> input -> additional dependencies.
[Usually managed code does not use dll export and import, it uses references, but that was unique situation.]
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 6 years ago.
I'm trying to learn how to use templated classes. I've created a simple templated class numbers that holds 2 numbers that can be any data type. Then I made a method that returns the bigger number of the two in the object. For some reason I keep getting linker errors though... Here's the errors and code. Not sure what's wrong, Visual Studio didn't underline anything in my code.
They say "unresolved external symbol" if it's too small to read.
templated.h
template <class T>
class numbers {
public:
numbers(T x, T y);
T bigger();
private:
T a, b;
};
templated.cpp
#include "templated.h"
#include <iostream>
using namespace std;
template <class T>
numbers<T>::numbers(T x, T y) {
a = x;
b = y;
}
template <class T>
T numbers<T>::bigger() {
return a > b ? a : b;
}
main.cpp
#include <iostream>
#include "templated.h"
using namespace std;
int main() {
numbers <int>pair(1, 2);
cout << pair.bigger() << endl;
return 0;
}
Thanks for reading!
You're not supposed to put template implementations in a cpp/c file. Move them all to your .h file.
This is because cpp files are supposed to take functions that compile into implementation libraries (like dll files or compiled objects), while template functions have undefined types (yet), whose types get defined at compile time.
You can, however, put specializations of your template functions in the cpp file, where you specify what types you want to include in your compiled objects.
This question already has answers here:
Defining static const integer members in class definition
(7 answers)
Closed 8 years ago.
I have the following classes:
MessageConstants.h:
class MessageConstants
{
public:
...
static const int ErrorDescriptionLength = 256;
...
};
SystemMessage.h:
class EvtError
{
private:
struct MsgData
{
int errorCode;
char errorDescription[MessageConstants::ErrorDescriptionLength];
}__attribute__((packed)) msgData;
public:
EvtError(int errorCode, string errorDescription);
inline void setErrorDescription(string desc){memcpy(msgData.errorDescription, desc.c_str(),
min(MessageConstants::ErrorDescriptionLength, (int)desc.length()));}
};
SystemMessage.cpp:
EvtError::EvtError(int errorCode, string errorDesc)
{
memset(&msgData, '\0', sizeof(msgData));
msgData.errorCode = errorCode;
memcpy(msgData.errorDescription, errorDesc.c_str(), min(MessageConstants::ErrorDescriptionLength, (int)errorDesc.length()));
}
I got the following link error on SystemMessage.cpp statement memcpy(msgData.errorDescription, errorDesc.c_str(), min(MessageConstants::ErrorDescriptionLength, (int)errorDesc.length())); :
In function EvtError::EvtError(int, std::string):
undefined reference to MessageConstants::ErrorDescriptionLength
collect2: error: ld returned 1 exit status
make: [link] Error 1
If I replace the MessageConstants::ErrorDescriptionLength with sizeof(msgData.errorDescription), the link error disappear.
My questions:
Why it doesn't complain the MessageConstants::ErrorDescriptionLength in the SystemMessage.h file, where there are two places with it?
How to avoid above link error?
The signature of min is:
template <typename T>
const T& min(const T&, const T&);
It takes its inputs by reference - which requires them to have storage. Your constant:
static const int ErrorDescriptionLength = 256;
Does not currently have storage. There are two ways to approach this. First, you can just add storage in your .cpp:
const int MessageConstants::ErrorDescriptionLength;
Second, you can just cast it to an int:
min((int)MessageConstants::ErrorDescriptionLength, (int)errorDesc.length())
// ^^^^^
Static variable must have a definition outside the class:
const int MessageConstants::ErrorDescriptionLength ;
This should go in exactly one .cpp. file in your project.
Sometimes you can get away without it, but in those cases it is either because the variable was not odr-used, or the program was ill-formed (but ODR violations don't require diagnosis).
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
Is it possible to pass the template-parameters to a function somewhere else defined?
For instance I have the class
Barrier.pp
template<Location L, Knock K>
class Barrier
{
//...
void checkBarrier( ... )
{
BarrierBest_checkBarrier<L, K>( ... );
}
//...
}
Other.cpp
template<Location L, Knock K>
BarrierBest_checkBarrier( ... )
{
//Use L and K to do call other function
}
As I have it right now the compiler throws a unresolved external symbol for all the possible combinations of the template parameters, that is, BarrierBest_checkBarrier<1,1>, BarrierBest_checkBarrier<1,0>, BarrierBest_checkBarrier<0,1>, BarrierBest_checkBarrier<0,0>
Is there a way to make this work?
If there are a limited number of combinations, you can explicitly instantiate your template, allowing you to keep your code separated between header and source files.
Put this at the bottom of your source file
template void BarrierBest_checkBarrier<0, 0>(...);
template void BarrierBest_checkBarrier<0, 1>(...);
template void BarrierBest_checkBarrier<1, 0>(...);
template void BarrierBest_checkBarrier<1, 1>(...);
If you want other files calling your function to pick their own parameters not in this list, you must put the whole templated code into a header file.
The problem may be that your templated functions are in cpp files, not in headers. The template parameters have to be known at the compile time. If you have separate compilation units, they are not.