Call object's method within template - c++

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!

Related

Initialize static variable inside the header file using template

Initialization of a static variable at the header file by using the templates (Used c++11, the 'inline' approach not supported)
cat base_class.hpp
#include <string>
#ifndef PROGRAM_BASE
#define PROGRAM_BASE
template <typename T>
struct S
{
static std::string s_elfName;
};
template <typename T>
std::string S<T>::s_elfName; //static initialization
class program_base : public S<void>{
public:
static std::string GetElfName() { return S<std::string>::s_elfName; }
bool update_string();
};
#endif
cat base_class.cpp
#include "base_class.hpp"
bool program_base::update_string(){
S<std::string>::s_elfName = "UpdateString";
}
cat read_string.cpp
#include <iostream>
#include "base_class.hpp"
using namespace std;
int main () {
program_base pb; pb.update_string();
cout << program_base::GetElfName() << endl;
}
The above one works fine, When I try to add templet inside the "class program_base"
cat base_class.hpp
#include <string>
#ifndef PROGRAM_BASE
#define PROGRAM_BASE
class program_base {
public:
template <typename T>
struct S
{
static std::string s_elfName;
};
template <typename T>
std::string S<T>::s_elfName; //static initialization
static std::string GetElfName() { return S<std::string>::s_elfName; }
bool update_string();
};
#endif
it's giving an error as " error: member 's_elfName' declared as a template"
Why I'm not able to declare a template inside the class instead of inheriting it?
As stated in the C++ Std. Nested class declaration:
Member functions and static data members of a nested class can be defined in a namespace scope enclosingthe definition of their class.
[Example:
struct enclose {
struct inner {
static int x;
void f(int i);
};
};
int enclose::inner::x = 1;
void enclose::inner::f(int i) { /* ... */ }
— end example]
If you take the definition out of outer class then it should be fine:
template <typename T>
std::string program_base::S<T>::s_elfName;
Since C++17 you can also do inline static initializing:
class program_base {
public:
template <typename T>
struct S
{
inline static std::string s_elfName;
};
static std::string GetElfName() { return S<std::string>::s_elfName; }
bool update_string();
};

How to use custom class pointer comparator inside class being compared

I am trying to use a custom comparator as in the following minimal example:
#include <set>
using namespace std;
struct idComp;
class TestClass
{
public:
int id;
void setId(int i){ id = i; }
int getId(){ return id; }
void test( set<TestClass*, idComp> &s){
//do my stuff
}
void test2(){
set <TestClass*, idComp> s;
}
};
struct idComp
{
bool operator() (TestClass* t1, TestClass* t2) const
{
return t1->getId() < t2->getId();
}
};
int main(int argc, char* argv[])
{
return 0;
}
...but when I try to compile I get the following error relating to the test function:
comp_ref.cpp:12:34: error: ‘idComp’ was not declared in this scope
void test( set<TestClass*, idComp> &s){
^~~~~~
comp_ref.cpp:12:40: error: template argument 2 is invalid
void test( set<TestClass*, idComp> &s){
and this with the addition of test2:
/usr/include/c++/7/bits/stl_tree.h:708:31: error: invalid use of incomplete type ‘struct idComp’
_Rb_tree_impl<_Compare> _M_impl;
Any suggestions of how/where to define idComp so that it is usable by the function test?
Since you have a bit of a circular dependency, you can resolve this by forward-declaring idComp before TestClass:
struct idComp;
class TestClass
{
...
But you can leave the definition of struct idComp where it is.

printing the contents of function template taking class pointer

I have difficulty in printing the string value present in a class used inside a function template.
Following is the code
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
using namespace std;
template <typename T>
class Test1{
public:
int val1 = 10;
string val2 = "hello";
};
class Test2{
public:
int val1 = 20;
string val2 = "hai";
};
class Queue{
public:
void append(T & item)
{
{
std::lock_guard<std::mutex> lock(mutex);
cout<<"string to be added "<<item->val2;
mQueue.push_back(item);
}
}
private:
std::vector<T> mQueue;
};
int main(int argc, char** argv) {
Test2 *new_val;
Queue *data;
data->append(new_val);
return 0;
}
Can anyone pl point out the error and what can be done to print the strings of various classes inside the function template.
Attention: when you write
template <typename T>
class Test1{
public:
int val1 = 10;
string val2 = "hello";
};
class Test2{
public:
int val1 = 20;
string val2 = "hai";
};
// ...
you define Test1 as a template class, Test2 and the following classes as ordinary (not template) classes.
So, when you write
class Queue{
public:
void append(T & item)
{
{
std::lock_guard<std::mutex> lock(mutex);
cout<<"string to be added "<<item->val2;
mQueue.push_back(item);
}
}
private:
std::vector<T> mQueue;
};
the compiler doesn't know what is T because T is the template parameter of Test1.
I suppose you want a template Queue
template <typename T>
class Queue{
// ...
};
// ...
Test2 new_val;
Queue<Test2> data;
data.append(new_val);
Observe that I've also trasformed the pointers in object.
Suggestion: avoid pointer until it's clear to you as use they.

templates and static objects (undefined reference & required from)

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;

How can I perform different actions for different template parameters in a template class?

If I want to make a template class, and depending on the typeid of the template parameter perform different actions, then how do I code this?
For instance, I have the following template class, in which I want to initialize the member field data depending on whether it is an int or a string.
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
};
// Implementation of constructor
template <class T>
A<T>::A()
{
if (typeid(T) == typeid(int))
{
data = 1;
}
else if (typeid(T) == typeid(std::string))
{
data = "one";
}
else
{
throw runtime_error("Choose type int or string");
}
}
This code would not compile however, with the following main file.
#include "stdafx.h"
#include "A.h"
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
A<int> one;
return 0;
}
The error is: error C2440: '=' : cannot convert from 'const char [2]' to 'int', which means the code is actually checking the else-if statement for an int, even though it will never be able to reach that part of the code.
Next, following this example (Perform different methods based on template variable type), I tried the following A.h file, but I got several linker errors mentioning that A(void) is already defined in A.obj.
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
~A();
};
// Implementation of constructor
template <>
A<int>::A()
{
data = 1;
}
template <>
A<std::string>::A()
{
data = "one";
}
Does anybody know how to get this code up and running? I also realize that using such an if-else statement in a template class might remove the power from a template. Is there a better way to code this?
EDIT: after discussion with Torsten (below), I now have the following A.h file:
#pragma once
#include <string>
// Class definition
template <class T>
class A
{
public:
A();
~A();
private:
T data;
};
// Implementation of initialization
template < class T >
struct initial_data
{
static T data() { throw runtime_error("Choose type int or string"); }
};
template <>
struct initial_data< int >
{
static int data() { return 1; }
};
template <>
struct initial_data< std::string >
{
static std::string data() { return "one"; }
};
// Definition of constructor
template <class T>
A<T>::A()
: data( initial_data< T >::data() )
{
}
and the following main:
#include "stdafx.h"
#include "A.h"
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
A<int> ione;
return 0;
}
The linker error I now get is: Test template 4.obj : error LNK2019: unresolved external symbol "public: __thiscall A::~A(void)" (??1?$A#H##QAE#XZ) referenced in function _wmain
Explicit specializations are the way to go.
I assume that you are including your A.h in several .cpp, and that's the root cause of your problem.
Specializations are definitions and there must be only one definition of A::A() and A::A() and so they must be in only one .cpp.
You'll have to move the explicit specialization in a .cpp
template <>
A<int>::A()
{
data = 1;
}
template <>
A<std::string>::A()
{
data = "one";
}
and keep a declaration for them in A.h
template<> A<int>::A();
template<> A<std::string>::A();
so that the compiler knows they are explicitly specialized and doesn't try to add automatic one.
Edit: with these four files, g++ m.cpp f.cpp a.cpp doesn't show any errors.
// a.h
#define A_H
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
};
template<> A<int>::A();
template<> A<std::string>::A();
#endif
// a.cpp
#include "a.h"
template <>
A<int>::A()
{
data = 1;
}
template <>
A<std::string>::A()
{
data = "one";
}
// f.cpp
#include "a.h"
int f()
{
A<int> one;
A<std::string> two;
}
// m.cpp
#include "a.h"
int f();
int main()
{
A<int> one;
A<std::string> two;
f();
}
You are correct in the second solution, what you need is template specialisation (keeping declaration and implementation together):
#include <string>
template <class T>
class A
{
private:
T data;
public:
A();
~A();
};
template <>
class A <std::string>
{
private:
std::string data;
public:
A() { data = "one"; }
};
template <>
class A <int>
{
private:
int data;
public:
A() { data = 1; }
};
If I may suggest a more elegant solution, then I would add a parameter to the constructor and avoid the template specialisation:
template <class T>
class A
{
private:
T data;
public:
A( T value ) : data( value ) {}
virtual ~A() {}
};
In case it's just the c'tor where you want to have behavior that depends on T, I would suggest to factor this out to a different struct:
template < class T >
struct initial_data
{
static T data() { throw runtime_error("Choose type int or string"); }
};
template <>
struct initial_data< int >
{
static int data() { return 1; }
}
template <>
struct initial_data< std::string >
{
static std::string data() { return "1"; }
}
If you specialize a class on it's template parameter, the different specializations are totally different types and can have different sets of data and functions.
Finally:
template <class T>
A<T>::A()
: data( initial_data< T >::data() )
{
}
kind regards
Torsten