C2039 - FUNCTION Is not a member of CLASS - c++

I'm experimenting a little bit with templated classes and I have found this error:
Error C2039 'getName': is not a member of 'Person<T>
This is my class structure:
struct professor
{
static const char name[];
static const age = 50;
};
struct student
{
static const char name[];
static const age = 21;
};
const char professor::name[] = "Jules";
const char student::name[] = "Michael";
// Please make the Person template class here.
template <class T>
class Person
{
public:
Person();
char[] getName();
private:
T & m_Person;
};
template<class T>
Person<T>::Person()
{
m_Person= T;
}
template<class T>
char* Person<T>::getName()
{
return m_Person.name;
}
Do you know what is failing?
In fact I don't know if the class definition etc are correct because I'm quite new with the templated classes so If you see any other error It would be great If you warn me.
THank you, I hope you can help me.

Fix compilation errors from first to last. char[] is not a valid return type, the function definition for getName() fails to compile that's why you get the error.
You are also missing the type specifier for the age member variables as C++ does not support default int.
Your code is a little confusing, I think you want something like this:
#include <string>
#include <iostream>
struct professor
{
std::string name;
int age;
};
struct student
{
std::string name;
int age;
};
template <class T>
class Person
{
public:
Person(const T& person) : m_Person(person) {}
std::string getName()
{
return m_Person.name;
}
private:
T m_Person;
};
int main() {
student s{"Michael", 21};
Person<student> p(s);
std::cout << p.getName();
return 0;
}
If you want to use a class with only static members as a template parameter, you don't need to store an instance:
#include <iostream>
struct S {
static const int x = 42;
};
template <typename T>
struct A {
int getValue() {
return T::x;
}
};
int main() {
A<S> a;
std::cout << a.getValue();
return 0;
}

Related

Passing a class object into a template function. C++

I have a template function defined as follows:
template<class T>
string toString(T value) {
ostringstream ss;
if (is_same<T, Student>::value) {
ss << value.getFirst() << ":" << value.getLast() << ":" << value.getId() << ":" << value.getGpa();
return ss.str();
}
else {
//ss << value;
return ss.str();
}
}
If i were to call this function like so:
int main(){
Student studentObj;
toString(studentObj);
}
How do i access this classes various members from the toString function?
I have tried (errors commented)
value.getId() //Returns int
//Error C2228 left of '.getId' must have class/struct/union
and
value<Student>.getId()
//Error C2275 'Student': illegal use of this type as an expression
Thanks in advance!
edit: Class definition
class Student {
protected:
std::string firstname;
std::string lastname;
int id;
float gpa;
public:
Student();
Student(std::string, std::string, int, float);
Student(const Student &);
std::string getFirst();
std::string getLast();
int getId();
float getGpa();
};
No. You cannot do that. With second phase of template code compilation for any non-Student type the if part will fail to compile. Not that if is runtime, not compile time, even though std::is_same is compile time. When you call it as toString(10) the compiler still has to compile it fully for int. It won't evaluate runtime if statement and eliminate the if (true) block - compiler still has to compile it, and produce object code for it. And hence the error.
You just need to specialize it:
template<class T>
string toString(T value)
{
ostringstream ss;
/// skipped code
return ss.str();
}
// SPECIALIZE for 'Student'
template<>
std::string toString(Student s)
{
// Code here
}
Add const and/or & if you want to.
To access the member functions of a class through template function, try calling this way.
Student studentobj;
std::string temp = toString<Student>(studentobj); // This will invoke the member functions of student class
// Code snippet similar to your query
class test
{
public:
test(){}
void callme()
{
std::cout<<"In callme function"<<std::endl;
}
};
template<class T>
void sample(T obj)
{
std::cout<<"In sample function"<<std::endl;
obj.callme();
}
int _tmain(int argc, _TCHAR* argv[])
{
test obj;
sample<test>(obj);
return 0;
}
Output:
In sample function
In callme function

Use both type and integer as template parameter

For the code I am working on, I have a class that uses a "context" singleton. In order to be a bit more coder-friendly, I passes the Singleton class used as a template to the object. For example, something like this:
#include <iostream>
class DefaultCtx {
private:
DefaultCtx() {};
const char *str = "default";
public:
static const char* get()
{
static DefaultCtx instance;
return instance.str;
}
DefaultCtx(DefaultCtx const &) = delete;
void operator=(DefaultCtx const &) = delete;
};
// Context for 64bits.
class Ctx64 {
private:
Ctx64() {};
const char *str = "64";
public:
static const char* get()
{
static Ctx64 instance;
return instance.str;
}
Ctx64(Ctx64 const &) = delete;
void operator=(Ctx64 const &) = delete;
};
template<typename Ctx>
class UsesCtx {
public:
UsesCtx() { std::cout << "Constructed using singleton " << Ctx::get() << std::endl; }
};
This scheme works fine, and I'm quite happy with the need to pass context as template parameter when constructing my objects. However, since Ctx64 is used for 64 bits representation, I wanted to add a little syntaxic sugar and use UsesCtx<64> :
int main() {
UsesCtx<DefaultCtx> a;
UsesCtx<Ctx64> b;
// UsesCtx<64> c; //< I don't know how to achieve that.
}
As I noted here, I don't know how to achieve it. I tried to redefine the class with an integer template, but that gives me the following error (compiled with g++ example.cpp --std=c++14)
// Gives compile error "error: template parameter ‘class Ctx’ redeclared here as ‘int n’"
template<int n>
class UsesCtx {
public:
UsesCtx() { std::cout << "Constructed using singleton " << n << std::endl; }
};
Is there any way I can have my class UsesCtx with both a class template parameter and an int template parameter? Of course, I can always instantiate with UsesCtx<Ctx64>, so this is not vital. But it didn't expected it to be hard to do.

How to use an integer id to identify a class in a class hierarchy automatically?

For example, I have a base class A and its sub-classes B, C and so on. B and C can also has its sub-classes. The structure is a tree with root A. And each class in the tree is assigned a different integer to identify itself. There is no restriction on the integer id's values and orders. Just make sure they are different for different classes.
My question is how to do it smartly (or automatically) by using like template techniques since manual assignment is error-prone. Any way to get the id is fine, like
class A
{
public:
static const id = ...;
};
or
template<class A>
struct Id
{
enum { value = ... };
};
Easiest way is just a function
int nextId() {
static int rval = 1;
return rval++;
}
class A { public: static const id = nextId(); };
class B { public: static const id = nextId(); };
class C { public: static const id = nextId(); };
That will work so long as you do not need to use the IDs in dynamic initialization at the start of the program.
Edit: if that is not sufficient, the next step up is to do the same thing with static variables in a template. This works across compilation units, but is still dynamic initialization time.
template <typename DummyT = void>
struct CommonCounter
{
public:
static int nextId() {
static int rval = 1;
return rval ++;
}
};
template <typename T>
struct IdFor
{
static int value()
{
static int rval = CommonCounter<>::nextId();
return rval;
}
};
class A { public: static const id = IdFor<A>::get(); };
You could do something like this. This should give the same order on the same compiler. You could also modify how you key things to get a known order and detect problems at initialisation time. Simple implementation, not tested.
#include <typeinfo>
class A {
public:
virtual ~A();
static void register_type(std::type_info const& t);
int id() const;
};
template<class T>
struct DoInitA
{
DoInitA() { A::register_type(typeid(T)); }
};
class B : public A
{
static DoInitA<B> s_a_init;
public:
~B() { }
};
//
// Implementation file.
//
#include <vector>
#include <functional>
namespace {
struct TypeinfoLess {
typedef std::reference_wrapper<const std::type_info> value_type;
bool operator()(value_type const& lhs, value_type const& rhs) const {
return lhs.get().before(rhs.get());
}
};
}
typedef std::vector<std::reference_wrapper<const std::type_info>> TypeVector;
static TypeVector s_types;
static bool s_init_complete = false;
A::~A() { }
void A::register_type(std::type_info const& t)
{
static int s_counter = 0;
if (s_init_complete)
throw std::runtime_error("Late initialisation");
s_types.push_back(std::reference_wrapper<const std::type_info>(t));
}
int A::id() const
{
if (!s_init_complete) {
sort(s_types.begin(), s_types.end(), TypeinfoLess());
s_init_complete = true;
}
for (size_t i = 0; i < s_types.size(); ++i)
if (s_types[i].get() == typeid(*this)) return i;
throw std::runtime_error("Uninitialised type");
}

Specialization of template method - what's wrong with my code?

What's wrong with this code?
class School {
public:
template<typename T> size_t count() const;
private:
vector<Boy*> boys;
vector<Girl*> girls;
};
template<> size_t School::count<Boy>() const {
return boys.size();
}
My compile says
error: specialization of ‘size_t School::count() [with T = Boy]’
after instantiation
Could you please help?
ps. This is how I'm going to use it later:
School s;
size_t c = s.count<Boy>();
You are missing a semi-colon.
class School {
public:
template<typename T> size_t count() const;
private:
vector<Boy*> boys;
vector<Girl*> girls;
}; // <-- Missing semi-colon
template<> size_t School::count<Boy>() const {
return boys.size();
}
Have you accidentally called count<Boy> in School before it is declared? One way to reproduce your error is
class Boy;
class Girl;
class School {
public:
template<typename T> size_t count() const;
size_t count_boys() const { return count<Boy>(); }
// ^--- instantiation
private:
std::vector<Boy*> boys;
std::vector<Girl*> girls;
};
template<> size_t School::count<Boy>() const { return boys.size(); }
// ^--- specialization
int main () { School g; return 0; }
You need to move the definition of count_boys() after all template members are specialized.
This compilable code compiles and runs OK with g++:
#include <vector>
using namespace std;
struct Boy {};
struct Girl {};
class School {
public:
template<typename T> size_t count() const;
private:
vector<Boy*> boys;
vector<Girl*> girls;
};
template<> size_t School::count<Boy>() const {
return boys.size();
}
int main() {
School s;
size_t c = s.count<Boy>();
}
In future, please make more effort to post compilable code - in other words, code with the necessary header files and supporting classes.

How to allow template function to have friend(-like) access?

How does one modify the following code to allow template function ask_runUI() to use s_EOF without making s_EOF public?
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
class AskBase {
protected:
std::string m_prompt;
std::string m_answer;
virtual bool validate(std::string a_response) = 0;
public:
AskBase(std::string a_prompt):m_prompt(a_prompt){}
std::string prompt(){return m_prompt;}
std::string answer(){return m_answer;}
static int const s_EOF = -99;
static int const s_BACKUP = -1;
static int const s_OK = 1;
int ask_user();
};
template<typename T> class Ask : public AskBase{
public:
Ask(std::string a_prompt):AskBase(a_prompt){}
bool validate(std::string a_response);
};
template<> bool Ask<std::string>::validate(std::string a_response){return true;}
template<> bool Ask<int>::validate(std::string a_response){int intAnswer;
return (std::stringstream(a_response) >> intAnswer);}
int AskBase::ask_user(){
for(;;){
std::cout << "Enter " << m_prompt;
std::string response;
getline(std::cin, response);
if (std::cin.eof())
return s_EOF;
else if (response == "^")
return s_BACKUP;
else if (validate(response)){
m_answer = response;
return s_OK;
}
}
return s_EOF;
}
template<typename T> int ask_runUI(T& a_ui){
int status = AskBase::s_OK;
for (typename T::iterator ii=a_ui.begin();
status!=AskBase::s_EOF && ii!=a_ui.end();
ii+=((status==AskBase::s_BACKUP)?((ii==a_ui.begin())?0:-1):1)
status = (*ii)->ask_user();
return (status == AskBase::s_OK);
}
int main(){
std::vector<AskBase*> ui;
ui.push_back(new Ask<std::string>("your name: "));
ui.push_back(new Ask<int>("your age: "));
if (ask_runUI(ui))
for (std::vector<AskBase*>::iterator ii=ui.begin(); ii!=ui.end(); ++ii)
std::cout << (*ii)->prompt() << (*ii)->answer() << std::endl;
else
std::cout << "\nEOF\n";
}
If you want a template function to be a friend, you must say so in the class declaration. Change the line that declares the friend function to this:
template <typename T>
friend int ask_runUI(T& a_ui);
Now, if your class is itself a template, things get a lot more complicated. Template friends are not trivial to do correctly. For that, I'll refer you to what C++ FAQ Lite says on the subject.
This worked for me!
class AskBase {
public:
AskBase(){}
template<typename T>
friend int ask_runUI(T& a_ui);
private:
static int const s_EOF = -99;
static int const s_BACKUP = -1;
static int const s_NULL = 0;
static int const s_OK = 1;
};
//int ask_runUI()
template<typename T>
int ask_runUI(T& a_ui)
{
return AskBase::s_NULL;
}
The simplest is probably to replace static int const members with enumeration and not mess with friends:
class AskBase {
public:
enum { Eof = -99, Null = 0, Ok = 1, Backup = -1 };
...
};