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.
Related
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;
}
[Solved]: The problem was not in template class initialization, but with code-specific issue of using undefined macro inside a template class constructor. The compiler error did not complain about undefined symbol, but was (wrongfully) related to lambdas.
I've searched for an answer but couldn't find an exact one. The closest answer is here: C++ invoke explicit template constructor but I'm not sure if that is entirely related to my question.
And my question is, how can I initialize a member of structure B in initialization list if the member is a template class?
Header ClassA.h:
#ifndef _A_
#define _A_
#include <typeinfo>
#include <windows.h>
template<class Type> class A{
int u,v;
Type** pointer;
public:
A();
A(int number);
~A();
Type& operator[] (int i){
typeid(Type);
return *pointer[i];
}
Type& Get(int i)
{
typeid(Type);
return *pointer[i];
}
Type *GetPointer(int i)
{
typeid(Type);
return pointer[i];
}
Type* add ();
Type& add(Type *element);
Type& add(Type *element, int place);
void expand(int NewLength);
void swap(Type *element, int place);
void remove(int number);
void remove(Type *element);
void removePointer(int number);
void removePointer(Type *element);
};
template<class Type>A<Type>::A(){
u = 128;
v = 10;
}
template<class Type>A<Type>::A(int number){
//some thing to do with number;
u = number;
v = 10;
New( pointer, Type *[u] );
}
template <class Type> A<Type>::~A()
{
}
template <class Type> void A<Type>::expand(int NewLength)
{
Type **NewList = NULL;
NewList = new Type*[NewLength];
}
template <class Type> Type* A<Type>::add ()
{
pointer[u] = new Type;
}
template <class Type> Type& A<Type>::add(Type *element)
{
}
template <class Type> Type& A<Type>::add(Type *element, int place)
{
}
template <class Type> void A<Type>::swap(Type *element, int place)
{
}
template <class Type> void A<Type>::remove(Type *element)
{
}
template <class Type> void A<Type>::removePointer(int nume)
{
}
template <class Type> void A<Type>::removePointer(Type *element)
{
}
#endif
Header StructB.h:
#pragma once
#ifndef _B_
#define _B_
#include "ClassA.h"
struct C{
float x,y,z;
};
struct B{
private:
B(){
}
public:
int x,y;
A<B*> member1;
A<C> member2;
B(int X,int Y) : member1(5),member2(5) {
//initialize x,y
}
void Add(B* otherB){
B** _pOtherB = new B*; (*_pOtherB) = otherB;
member1.add(_pOtherB);
}
};
#endif
The compiler complains with this error (and some other errors, I can post them if nedded):
error C3493: 'number' cannot be implicitly captured because no default capture mode has been specified
Is there any way to do this, or some workaround perhaps?
Thanks in advance :D
Either the code you've given us isn't complete, or it is broken. This line:
New(pointer, Type *[u]);
seems to be referencing either some missing member method or global function, or it is simply invalid. The error message is kinda cryptic, but that's C++ for you.
I'm going to assume that New is some kind of macro, because no normal function (even a templated one) can take this sort of type definition as a parameter. You've not given us the definition of New, so there's no way we can tell. It is probably the absense of this macro (maybe a wrapper for some sort of memory debugging system?) that is causing the crazy error.
If I replace the New line with this:
pointer = new Type*[u];
the code compiles fine.
I'm using class templates which contain virtual functions in my current project, and I stumbled upon a problem I can't overcome on my own.
Class templates cannot have their member function bodies split from class
definition in .hpp file because of linker errors. I don't want to
instantiate my templates for each new type I'm abut to use, so all
that's left is to leave them inlined. This is absolutely
fine as they are 1-2 lines long most of the time, so I'm not going
to experience any code bloat.
On the other hand, gcc creates vtable for a polymorphic class in
.cpp file that has definition of the first non-inline function that
is declared in the class definition. Since I have all member
functions inline, I'm getting undefined reference to vtable, or no
RTTI symbol found for my class in GDB.
Please consider the following code:
template <typename T>
struct Test
{
virtual void testMe() const = 0;
virtual ~Test() = default;
};
template <typename T>
struct test : public Test<T>
{
virtual void testMe() const
{
std::cout << typeid(T).name() << std::endl;
}
virtual ~test() = default;
};
int main()
{
test<int> t;
Test<int>& T = t;
T.testMe();
return 0;
}
In this particular example I'm getting:
can't find linker symbol for virtual table for `test<int>' value
when debugging with GDB.
How do I force my compiler to put vtable in a specific cpp file when all class functions are inline?
EDIT:
Since the example provided above didn't illustrate the problem, here's my original code.
The class that's causing the problem:
#ifndef CONVERTIBLETO_H
#define CONVERTIBLETO_H
#include "convertibleTo_converters.h"
#include <functional>
template <
typename IT,
template <typename InterfaceType, typename ErasedType>
class Converter = convertibleTo_detail::default_converter
>
class convertibleTo
{
public:
typedef convertibleTo<IT, Converter> this_type;
typedef IT InterfaceType;
struct is_type_eraser_tag {};
private:
class holder_interface
{
public:
virtual InterfaceType get() const = 0;
virtual void set(const InterfaceType&) = 0;
virtual holder_interface* clone() const = 0;
virtual ~holder_interface() {}
};
template <typename ErasedType>
class holder : public holder_interface
{
public:
virtual InterfaceType get() const
{
return (Converter<InterfaceType, ErasedType>::convert(this->data));
}
virtual void set(const InterfaceType& value)
{
this->data = (Converter<InterfaceType, ErasedType>::convert(value));
}
virtual holder_interface* clone() const
{
return new holder(*this);
}
holder() = delete;
holder(const holder& other):
data(other.data)
{ }
holder(ErasedType& d):
data(d)
{ }
virtual ~holder() = default;
private:
ErasedType& data;
};
public:
inline InterfaceType get() const
{
if (this->held)
return this->held->get();
else
return InterfaceType();
}
inline void set(const InterfaceType& value)
{
if (this->held)
this->held->set(value);
}
inline bool empty() const
{
return ! this->held;
}
convertibleTo<InterfaceType, Converter>& operator= (const convertibleTo<InterfaceType, Converter>& other)
{
if(this->held)
delete this->held;
this->held = other.held->clone();
return *this;
}
convertibleTo():
held(nullptr)
{ }
template <typename T>
explicit convertibleTo(T& data):
held(new holder<T>(data))
{
}
convertibleTo( convertibleTo& other ):
convertibleTo( const_cast<const convertibleTo&>(other))
{
}
convertibleTo( const convertibleTo& other ):
held(nullptr)
{
if(other.held)
this->held = other.held->clone();
}
~convertibleTo()
{
if (this->held)
delete this->held;
}
private:
holder_interface * held;
};
#endif
Required helper classes:
#ifndef CONVERTIBLETO_CONVERTERS_H
#define CONVERTIBLETO_CONVERTERS_H
#include <string>
#include <sstream>
namespace convertibleTo_detail
{
template <typename InterfaceType, typename ErasedType>
struct default_converter
{
static inline InterfaceType convert(const ErasedType& input)
{
return input;
}
static inline ErasedType convert(const InterfaceType& input)
{
return input;
}
};
template <typename T>
struct default_converter<T, T>
{
static inline T convert(const T& input)
{
return input;
}
};
template <typename ErasedType>
struct default_converter<std::string, ErasedType>
{
static inline std::string convert(const ErasedType& input)
{
default_converter<std::string, ErasedType>::prepareConverter();
default_converter<std::string, ErasedType>::converter << input;
return default_converter<std::string, ErasedType>::converter.str();
}
static inline ErasedType convert(const std::string& input)
{
default_converter<std::string, ErasedType>::prepareConverter(input);
ErasedType result;
default_converter<std::string, ErasedType>::converter >> result;
return result;
}
private:
static std::stringstream converter;
struct SetExceptionFlagsOnce
{
SetExceptionFlagsOnce()
{
default_converter<std::string, ErasedType>::converter.exceptions(std::stringstream::failbit);
}
};
static void inline prepareConverter(std::string value = "")
{
static SetExceptionFlagsOnce setter;
default_converter<std::string, ErasedType>::converter.clear();
default_converter<std::string, ErasedType>::converter.str(value);
}
};
template <typename ErasedType>
std::stringstream default_converter<std::string, ErasedType>::converter;
template <>
struct default_converter<std::string, std::string>
{
static inline std::string convert(const std::string& input)
{
return input;
}
};
}
#endif // CONVERTIBLETO_CONVERTERS_H
main.cpp:
#include <iostream>
#include "convertibleTo.h"
int main()
{
int I = 5;
convertibleTo< std::string > i(I);
std::cout << i.get() << std::endl;
i.set("321");
std::cout << i.get() << std::endl;
return 0;
}
Error I'm getting is:
RTTI symbol not found for class 'convertibleTo<std::string, convertibleTo_detail::default_converter>::holder<int>'
it's shown when I go inside i.get(), and then inside holder's get().
EDIT: Moved the full source from pastebin here, as per suggestion
Since the last two comments suggested that this is a GDB bug, how do I check this myself next time?
In case GDB complains about missing vtable - would confirming that I can access every virtual member through a reference to ABC initialized with derived class be enough to confirm that everything is OK?
In case GDB complains about missing RTTI symbol - would calling typeid() on the reference to ABC initialized with derived class to be enough to confirm that the RTTI symbol is, in fact, present?
Your code (the full version, with two header files and main.C) compiles and links without any errors for me, with gcc 4.8.3, with the default options (except for -std=c++11, to enable C++11 mode).
I even loaded the resulting executable into gdb. gdb swallowed it without any issues.
I don't see anything wrong here.
I don't know if it is possible, I checked on StackOverflow, I found a lot of stuff but nothing that really fit my problem (or I don't see the relation).
What I'd like to do is something like that:
class Bean
{
public:
Bean(){}
virtual ~Bean(){}
template <class T>
bool set_(T){return false;}
template <class T>
bool get_(T&){return false;}
};
template <class T>
class GenericBean: public Bean
{
protected:
T type;
};
class Prova : public GenericBean<int>
{
public:
Prova(){type = 0;}
template<int> bool set_(int value){ type=value;}
template<int> bool get_(int& value){value = type;}
};
I'd like to have on object like Prova, cast to Bean and get the specialized function,
What I want to do is something like this:
#include <vector>
#include "Bean.h"
using namespace std;
class VirtualMessage
{
public:
VirtualMessage(void){}
virtual ~VirtualMessage(void){}
template <class ReturnValue, class Item>
bool Get(ReturnValue & val)
{
for(size_t i = 0; i < m_vData.size(); i++)
{
if(m_vData[i].get_<ReturnValue>(val))
return true;
}
}
template <class Item, class Value>
bool Set(Value val)
{
Item bean;
if(bean.set_<Value>(val))
{
m_vData.push_back(bean);
return true;
}
return false;
}
protected:
vector<Bean> m_vData;
};
Main:
#include "VirtualMessage.h"
#include "Bean.h"
int main()
{
VirtualMessage msg;
if(msg.Set<Prova ,int>(4))
printf("Test 1 passed");
}
this code doesn't compile
Maybe nobody will use it, but I wrote something that fits my need. It's not perfect, I have to work on it but is a begin:
#define UNIQUE(T) unsigned int GetID(){return UniqueType<T>::id();}
struct UniqueTypeBase
{
static unsigned int _ids;
};
unsigned int UniqueTypeBase::_ids = 0;
template <class T>
struct UniqueType : public UniqueTypeBase
{
static const unsigned int id()
{
static unsigned int typeId = 0;
if (typeId == 0)
typeId = ++_ids;
return typeId;
}
};
template <class T>
class TemplateBean
{
public:
T m_tValue;
template<class T> set_(T){return false;}
template<class T> get_(T&){return false;}
bool set_(T value){ m_tValue = value; return true;}
bool get_(T& value) { value = m_tValue;return true;}
};
class Prova : public TemplateBean<int>
{
public:
UNIQUE(Prova)
Prova(){m_tValue = 0;}
};
class Prova2 : public TemplateBean<float>
{
public:
UNIQUE(Prova2)
Prova2(){m_tValue = 0;}
};
class VirtualMessage
{
public:
VirtualMessage(void){}
virtual ~VirtualMessage(void){}
template <class Item, class ReturnValue>
bool Get(ReturnValue & val)
{
Item a;
map<unsigned int, void*>::iterator it;
it = m_TagMap.find(a.GetID());
if(it != m_TagMap.end())
{
Item* pItem = reinterpret_cast<Item*>(it->second);
if(pItem->get_(val))
return true;
}
return false;
}
template <class Item, class Value>
bool Set(Value val)
{
Item* pBean = new Item();
if(pBean->set_(val))
{
m_TagMap[pBean->GetID()] = (void*)pBean;
return true;
}
return false;
}
protected:
map<unsigned int, void*> m_TagMap;
};
Test Main:
int main()
{
VirtualMessage msg;
if(msg.Set<Prova ,int>(4))
printf("Test 1 passed\n");
if(!msg.Set<Prova,float>(4.00))
printf("Test 2 succed\n");
if(msg.Set<Prova2,float>(4.00))
printf("Test 3 succed\n");
int a=0;
if(msg.Get<Prova>(a))
printf("%d = 4...if 4=4 test passed\n",a);
float b=0;
if(msg.Get<Prova2>(b))
printf("%f = 4...if 4=4 test passed\n",b);
getchar();
}
I think you misunderstood the use of templates.
Templates are blueprints to build classes or methods, that the compiler use to produce real classes and methods (which is called instantiation).
As such, they are purely a compile-time facility. Therefore, they cannot be virtual, and thus overloading a template method in a derived class does not mean what you expect. It hides the base class method when used from derived (statically) but you still call the base class method if you use a reference or pointer to the base class.
What you are trying to achieve is, unfortunately, impossible with templates: it requires a runtime check.
Furthermore, you are using a std::vector<Bean> which will not work as intended. Polymorphic types shall not be manipulated by values in C++, you need a std::vector< std::unique_ptr<Bean> > or boost::ptr_vector<Bean>...
I would recommend reading a good C++ primer before attempting the kind of task you have set yourself upon. You need a basic introduction to C++ paradigms... and gotchas. And there are a lot of gotchas.
So I can't use initializers in my class constructor because of using arrays, so I decided to use an init() method instead. Now I have a different problem. I have a class like this:
class EPWM {
private:
volatile EPWM_REGS* const regs;
public:
void init(volatile EPWM_REGS* _regs);
};
where I need to implement init() by initializing regs = _regs; but I can't because of the const. Is there a way to force the assignment in my init method? I would like to keep the const keyword so I don't accidentally reassign elsewhere.
edit: as much as I would like to use a constructor + initializer, which would solve this problem (my code used to do this), I cannot because I have another class which has an array of EPWM objects, and I can't initialize those objects because C++ does not support initializers for array members. (again, see the other question I asked a little while ago on this subject.)
Context for using EPWM is something like this:
class PwmGroup {
private:
EPWM *epwm;
void init(EPWM *_epwm) { epwm = _epwm; }
};
/* ... */
// main code:
EPWM epwm[3];
PwmGroup pwmGroup;
{
// EPwm1Regs, EPwm2Regs, EPwm3Regs are structs
// defined by TI's include files for this processor
epwm[0].init(&EPwm1Regs);
epwm[1].init(&EPwm2Regs);
epwm[2].init(&EPwm3Regs);
pwmGroup.init(epwm);
}
You could consider const_cast and pointers, but it's something best used very rarely. Something like...
EPWM_REGS** regsPP = const_cast<EPWM_REGS**>(®s);
*regsPP = _regs;
How about the following?
struct EPWM_array {
EPWM_array() { /* initialize array */ }
const EPWM *begin() const;
const EPWM *end() const;
EPWM array[ 10 ];
};
struct EPWMWrapper {
volatile EPWM_REGS* const regs;
EPWMWrapper(EPWM_array const& a) : regs(a.begin()) {}
};
Would something like this help? You can still intentionally violate the constness but it prevents normal people from silly mistakes (I haven't compiled this).
class EPWM {
private:
volatile EPWM_REGS* regs_for_init_never_use;
volatile EPWM_REGS* const& regs;
public:
EPWM() : regs(regs_for_init_never_use)
void init(volatile EPWM_REGS* _regs);
};
Playing devil's advocate: apart from the obvious documentation intent, since it's a private attribute, you could perfectly not use the const keyword and not modify it apart from the init method.
Your const_cast might actually be undefined behavior here, and I certainly prefer not to run in those dark corners, whatever the workarounds.
class EPWM {
private:
volatile EPWM_REGS* regs; // normally const, but need to be inited :/
public:
void init(volatile EPWM_REGS* _regs);
};
Although, revisit your question: while a raw array cannot be default constructed, you can write an array class that can be.
namespace detail
{
template <class T, size_t N, size_t index>
struct At
{
static T& Do(Array<T,N>& array)
{
return At<T,N-1,index-1>::Do(array.tail());
}
};
template <class T, size_t N>
struct At<T,N,0>
{
static T& Do(Array<T,N>& array) { return array[0]; }
};
template <class T, size_t index>
struct At<T,0,index> {};
template <class T>
struct At<T,0,0> {};
} // namespace detail
template <class T, size_t N>
class array
{
public:
typedef T value_type;
static const size_t Length = N;
array(): mHead(), mTail() {}
array(const array& rhs): mHead(rhs.mHead), mTail(rhs.mTail) {}
// Don't know whether it will be optimized or not
// Not sure I can use pointer arithmetic either :p
T& operator[](size_t index) { return index == 0 ? mHead : mTail[index-1]; }
// Compile time access
template <size_t index>
T& at() { return detail::At< T, N, index >::Do(*this); }
private:
T mHead;
array<T, N-1> mTail;
}; // class array<T,N>
template <class T>
class array<T,1>
{
public:
typedef T value_type;
static const size_t Length = 1;
array(): mHead() {}
array(const array& rhs): mHead(rhs.mHead) {}
T& operator[](size_t index) { return mHead; } // or error handling ;)
private:
T mHead;
}; // class array<T,1>
template <class T> class array<T,0> {}; // int[0] does not work (stack) so...
Okay... perhaps not as efficient as a real array... you can always turn to Preprocessor generation though:
template <class T>
class Array4
{
public:
Array4(): m0(), m1(), m2(), m3() {}
Array4(const Array4& rhs): m0(rhs.m0), m1(rhs.m1), m2(rhs.m2), m3(rhs.m3) {}
T& operator[](size_t index) { return *(&m0 + index); }
private:
T m0;
T m1;
T m2;
T m3;
}; // class Array4<T>
Use a constructor like this:
EPWM::EPWM(volatile EPWM_REGS* _regs)
: regs(_regs)
{}
Then simply have no params in init:
void EPWM::init()
{
// do something with this->regs here...
}
In other words, you can initialise everything in the class constructor - just not member arrays.