templates and static objects (undefined reference & required from) - c++

I'm implementing some ideas using templates and static members. Although the "real" code produces another error, this is the one which i still have on a toy example code
#include <string>
#include <iostream>
template<int dim>
class Class1 {
public:
Class1() {};
~Class1() {};
void foo() {
std::cout<<"foo-1"<<std::endl;
}
protected:
std::string name;
};
template<int dim>
class Class2 : public Class1<dim>
{
public:
Class2(const int & a, const int &b) :
number( Class2<dim>::id_generator++ )
{
Class1<dim>::name = "My-name";
foo(); // (1)
};
void foo() {
Class1<dim>::foo();
std::cout<<"foo-2"<<std::endl;
}
private:
const unsigned int number;
static unsigned int id_generator;
};
int main()
{
int a = 1, b=2;
Class2<2> class2(a,b); // (2)
}
with the linker error:
undefined reference to `Class2<2>::id_generator'
rea-life example produces 2 errors
(1) required from 'Class2<dim>::Class2(int, int) [with int dim = 3]'
(2) required from here.
that real-life errors tell me absolutely nothing at all! :(
I hope if the toy-problem is solved, the real-life one will be gone too,
but if anyone has any ideas on the "real-life" errors (those 2 lines) in the context of the structure, pls, let me know.

You forgot to add a definition for your static data member id_generator. Add this at global namespace level:
template<int dim>
unsigned int Class2<dim>::id_generator = 0;
With this addition, you can see your code correctly compiling and linking here.

Well, as the error message says, there is no definition of the static data member. If this was an ordinary class, you'd put the definition in a source file:
// header:
class C {
static int i;
};
// source:
int C::i = 3;
A template is a pattern; the compiler uses it to generate code. So what you want to end up with when the compiler instantiates the template is something like the preceding code. But template code goes in headers, not source files, so you write it like this:
// header:
template <class T>
class C {
static int i;
};
template <class T>
int C<T>::i = 3;

Related

'CustomVector<int,15>::size': cannot access private member declared in class 'CustomVector<int,15>'

I am so confused right now...
Here is the code that I will be talking about:
main.cpp:
#include "CustomVector.h"
#include <iostream>
int main() {
CustomVector<int, 15> hello{};
std::cout << hello.size() << '\n';
return 0;
}
CustomVector.h:
#pragma once
template<typename T, int S>
class CustomVector {
private:
T arr[S];
int size;
public:
CustomVector() : arr{}, size{ S } {}
// Methods
int size() const {
return size;
}
};
As you can see I am trying to use the size() method that I have in my class definition, which there shouldn't be a problem with, right..? But when I try to use it in main.cpp and try to print it out to the console, it is giving me the compiler error which my question title has. Why could this be, this has never happened to me before. I would think there is some sort of "redefinition" somehow, but how could that be, there couldn't be a redefinition if it is in my own user-defined class?

How can I get rid of the <error-type> type that is appearing in my method template? Both the input to the method and the class are templates

I am getting the error
declaration is incompatible with "void spectrogram<T>::update(<error-type> x)
I don't see any difference between the declaration and the definition of the method, not sure why it is complaining about just this one definition and not the constructor or destructor.
Here is vComplex.hpp
#ifndef VCOMPLEX_H
#define VCOMPLEX_H
template <class T>
class vComplex {
public:
T* realp;
T* imagp;
int length; // for bookkeeping
vComplex(void) { }
vComplex (T* I, T* Q, int len) {
realp = I;
imagp = Q;
length = len;
}
~vComplex(void) {
free(realp);
free(imagp);
}
void put(T* I, T*Q, int len) {
realp = I;
imagp = Q;
length = len;
}
};
#endif
the function declaration for update in spectrogram.hpp, with other members removed:
#ifndef SPECTROGRAM_H
#define SPECTROGRAM_H
template <typename T>
class spectrogram {
public:
void update(vComplex<T> x);
};
#endif
and the function signature (and includes) for update in spectrogram.cpp:
#include <stdio.h>
#include <math.h>
#include "spectrogram.hpp"
#include "vComplex.hpp"
template <typename T>
void spectrogram<T>::update(vComplex<T> x) {
//do stuff
}
In VS 2017, I get the red underline under update and everything inside of it breaks basically. VS is saying T is undefined which I'm assuming is caused by the overall error. I have to use dynamically allocated pointers, I don't have the option of using other types or containers.

Can't call a static method in Qt

I have a simple class containing a static attribute. There are two static methods in this class: one to get the static attribute and the other to initialize it. Yet when call the static method the compiler reports an error.
The class:
class Sudoku {
Cell Grid[9][9];
int CurrentLine;
int CurrentColumn;
void deleteValInColumn(int val, int col);
void deleteValInRow(int val, int row);
void deleteValInBox(int val, int x, int y);
static int unsetted; //!
public:
static void IniUnsetted() { //!
unsetted = 0;
}
static int GetUns() { //!
return unsetted;
}
Sudoku(ini InitGrid[9][9]);
void Calculate_Prob_Values();
Cell getCell(int x, int y);
QVector<int> getPossibleValues(int x, int y);
bool SolveIt();
};
This is the error I get:
In member function 'bool Sudoku::SolveIt()':
no return statement in function returning non-void [-Wreturn-type]
In function `ZN6Sudoku6GetUnsEv':
undefined reference to `Sudoku::unsetted` error: ld returned 1 exit status
You will need to define the static variable, even if it is not initialized explicitly. That is what is missing in your code. You should have provided a simple example to reproduce the issue, but for your convenience I am providing one which works.
main.cpp
class Foo {
public:
static int si;
static void bar();
};
int Foo::si = 0; // By default, it will be initialized to zero though.
void Foo::bar() {
Foo::si = 10;
};
int main()
{
Foo::bar();
return 0;
}
Note: I would suggest to get someone to review your code because "unsetted" is incorrect English. If we are at it, you would probably need to fix your indentation as well.
In your code there is no definition of unsetted, there is only declaration.
The solution is to put somewhere in your cpp file a line like this:
int Sudoku::unsetted
The reason for that is that each instantiation of Sudoku class will use the same unsetted member so it cannot be defined for each of them, so it's up to programmer to define it in one place only.
In your cpp file, define the static variable (ideally with an initialization):
int Sudoku::unsetted = 0;
If you are declaring any static variable in class, then you should define that variable outside the class also.
Example:
class A
{
public:
static int x; // declaration
};
int A::x; // definition

Call object's method within template

I have following code:
template<class T>
class TemplateA : public virtual std::list<T>
{
protected:
unsigned int iSize;
public:
unsigned int getSize();
};
/////////////
template<class T>
unsigned int TemplateA<T>::getSize()
{
return iSize;
}
/////////////
/////////////
/////////////
template<class T>
class TemplateB : public TemplateA<T>
{
public:
unsigned int calcSize();
};
/////////////
template<class C>
unsigned int TemplateB<C>::calcSize()
{
iSize = C.getSize;
return iSize;
}
/////////////
/////////////
/////////////
// Class C (seperate file) has to contain function getSize()
class CMyClass
{
public:
static const unsigned int getSize = 5;
};
This means, within class TemplateB I want to call the getSize method, which the passed class have defined.
I receive the following error message:
error C2275: 'C' : illegal use of this type as an expression
while compiling class template member function 'unsigned int TemplateB<C>::calcSize()'
1> with
1> [
1> C=CMyClass
1> ]
I'm quiet sure that this function worked under VS 2003... What's wrong with the method? Maybe a compiler setting? I don't know where to set what :(
You should say this->getSize or C::getSize; this will defer lookup to the second phase when the template arguments are known.
Hi you could simplify your code too whilst correcting, all you seem to have done is use C rather than TemplateB so if you do:
template<class C>
unsigned int TemplateB<C>::calcSize()
{
return c::getSize; //based on getSize being static
}
You will save the memory of an extra variable and it should work fine:)
Addendum:
Here is a working code snippet using your code as a basis:
#include <iostream>
#include <list>
using namespace std;
template<class T>
class TemplateA : public virtual std::list<T>
{
protected:
unsigned int iSize;
public:
unsigned int getSize();
};
template<class T>
unsigned int TemplateA<T>::getSize()
{
return iSize;
}
template<class T>
class TemplateB : public TemplateA<T>
{
public:
unsigned int calcSize();
};
template<class C>
unsigned int TemplateB<C>::calcSize()
{
return C::getSize;
}
// Class C (seperate file) has to contain function getSize()
class CMyClass
{
public:
static const unsigned int getSize = 5;
};
int main()
{
CMyClass classme;
TemplateB<CMyClass> test ;
cout <<"Calc size outputs: "<< test.calcSize() << endl;
return 0;
}
Apologies for the unchecked answer previously.
Hope this one helps!

Linking error with template classes

I have a class that needs to call an external function in a variety of different contexts. I want to keep things flexible, so I'm using an interface (inspired by the 3rd edition of Numerical Recipes) that should work with functors, function pointers, etc. A simplified example looks like:
class MyClass {
public:
template <class T>
MyClass(T &f_) { f = f_; }
private:
int (*f)(int);
};
int myFn(int i) {
return i % 100;
}
int main() {
MyClass test(myFn);
return 0;
}
So far so good; g++ compiles this without any complaints. In my real application, there's a lot more code so I've got things split up among multiple files. For example,
test2.h:
#ifndef __test2__
#define __test2__
class MyClass {
public:
template <class T>
MyClass(T &f_);
private:
int (*f)(int);
};
#endif
test2.cpp:
#include "test2.h"
template <class T>
MyClass::MyClass(T &f_) {
f = f_;
}
main.cpp:
#include "test2.h"
int myFn(int i) {
return i % 100;
}
int main() {
MyClass test(myFn);
return 0;
}
When I try to compile this using g++ test2.cpp main.cpp, I get the following linking error:
/tmp/ccX02soo.o: In function 'main':
main.cpp:(.text+0x43): undefined reference to `MyClass::MyClass<int ()(int)>(int (&)(int))'
collect2: ld returned 1 exit status
It appears that g++ isn't aware of the fact that I'm also trying to compile test2.cpp. Any ideas about what might be going on here?
Thanks,
--craig
Template classes must have their implementation visible to all translation units that use them, unless they are fully specialized.
That means you have to move the implementation in the header:
//test2.h
#ifndef __test2__
#define __test2__
class MyClass {
public:
template <class T>
MyClass(T &f_);
private:
int (*f)(int);
};
template <class T>
MyClass::MyClass(T &f_) {
f = f_;
}
#endif