I have a C++ program that I can't compile:
template <class T>
class Base
{
protected:
class BaseNode
{
public:
int i;
};
protected:
typedef void (*functionPointer)(const T &t, void *data);
virtual void apply( const functionPointer fn, void *data) const;
};
template <class T>
class Derived : public Base<T *>
{
public:
typedef void (*functionPointer)(const T *t, void *data);
virtual void apply( const functionPointer fn, void *data) const;
};
template <class T> void Derived<T>::apply( const functionPointer fn,
void *data) const
{
BaseNode *node ;
}
int main()
{
Derived<int > b;
}
when I try to compile it , I get the following error:
pankajk[]> g++ sample2.cpp
sample2.cpp: In member function 'virtual void Derived<T>::apply(void (*)(const T*, void*), void*) const':
sample2.cpp:26: error: 'BaseNode' was not declared in this scope
sample2.cpp:26: error: 'node' was not declared in this scope
I am new to concept of templates, and not able to figure out what I'm doing wrong.
Base<T *> is a dependent base-class, so you need to use an explicit scope and a typename keyword:
template <class T> void Derived<T>::apply(const functionPointer fn,
void *data) const
{
typename Base<T *>::BaseNode* node;
// ~~~~~~~^ ~~~~~~~~^
}
Related
For example, I have a class template:
template <typename T>
class base {
public:
void set(T data) { data_=data; }
private:
T data_;
};
And for a certain type I would like to add a function, but also have functions from the template class.
template <>
class base<int>{
public:
void set(int data) { data_=data; }
int get(){ return data_;} //function specific to int
private:
int data_;
}
How to do that without copying all members from the template class?
With inheritance:
template <typename T> struct extra {};
template <> struct extra<int> {
public:
int get() const;
};
template <typename T>
class base : public extra<T> {
friend class extra<T>;
public:
void set(T data) { data_=data; }
private:
T data_ = 0;
};
int extra<int>::get() const{ return static_cast<const base<int>*>(this)->data_;}
Demo
You can do this by using enable_if from type_traits to enable the get function only when the template parameter is int. One example is shown below.
#include <type_traits>
template <typename T>
class base {
public:
template <typename X=T,
std::enable_if_t< std::is_same<X,typename T>::value
&& std::is_same<X,int>::value, bool> = false>
int get() { return data_; }
void set(T data) { data_=data; }
private:
T data_;
};
I have template with overloaded method. I'm trying to create pointer to the overloaded method.
template<typename T>
class Future {
public:
const T& get() const;
bool get(T*, int timeoutMs) const;
};
...
const void*&(Future<void*>::*x)()const = &Future<void*>::get;
Compilation fails with this error:
no matches converting function 'get' to type 'const void*& (class Future<void*>::*)()const'
candidates are: const T& Future<T>::get() const [with T = void*]
bool Future<T>::get(T*, int) const [with T = void*]
I have tried to typedef Future<void*> without any luck.
If T is void* the const should be on the pointer not on the pointed memory:
void* const & (Future<void*>::*x)() const = &Future<void*>::get;
Templates themselves have no pointers. A template is a template, it tells c++ how to create a class. So
template<class T>
class Container {
public:
T* element() { return element_; }
void SetElement(Element *element) { element_ = element; }
typedef void (*SetElementFunctionPointer)(Element *element);
private:
T *element_;
};
typedef Container<int> IntContainer;
The code above shows you a Container template, and how you create an integer container (IntContainer) by using the Container template. In there I've declared a typedef for a SetElementFunctionPointer.
I have a template specialization class and I need to declare a function template as a friend to this class. I have already created the following code which compiles and works well on the MSVC compiler but it doesn't work on the code-warrior compiler. To make it work on the codewarrior compiler I have to uncomment the explicit declarations in the template specialization class.
Is this a problem with the codewarrior compiler or some problem with the code?
Reduced code size to give context:
//template class
template<class R>
class Alice
{
public:
Alice() {}
private:
R review;
template< class F>
friend void Watch(F, Movie::Wonderland< Alice<R> >&, int);
};
//template specialization class
template<>
class Alice<void>
{
public:
Alice() {}
private:
int review;
template<class F>
friend void Watch(F, Movie::Wonderland< Alice< void > >&, int);
/*
//explicit declaration
//need to uncomment this to compile on codewarrior
//as the function template above doesn't work.
friend void Watch<void (*)()>(void (*)(), Movie::Wonderland<Alice<void> > &, int);
*/
};
Full code:
#define ONCE 1
#define NULL
namespace Movie{
template<class C>
class Wonderland
{
public:
Wonderland():who(NULL){}
Wonderland(C* she):who(she){}
void Attach(C *she)
{who = she;}
C* operator->()
{return who;}
private:
C* who;
};
}
//fwd declarations
template<class R> class Alice;
void Watch(Movie::Wonderland< Alice<void> >& theatre, int price);
template<class F> void Watch(F func, Movie::Wonderland< Alice<void> >& theatre, int price);
template<class P, class F> void Watch(F func, P food, Movie::Wonderland< Alice<void> >& theatre, int price);
struct popcorn;
template<class R>
class Alice
{
public:
Alice() {}
private:
R review;
friend void Watch(Movie::Wonderland< Alice<R> >&, int);
template< class F>
friend void Watch(F, Movie::Wonderland< Alice<R> >&, int);
template<class P, class F>
friend void Watch(F, P, Movie::Wonderland< Alice<R> >&, int);
};
template<>
class Alice<void>
{
public:
Alice() {}
private:
int review;
friend void Watch(Movie::Wonderland< Alice< void > >&, int);
template<class F>
friend void Watch(F, Movie::Wonderland< Alice< void > >&, int);
template<class P, class F>
friend void Watch(F, P, Movie::Wonderland< Alice< void > >&, int);
/*
//explicit declarations
friend void Watch(Movie::Wonderland<Alice<void> > &, int);
friend void Watch<void (*)()>(void (*)(), Movie::Wonderland<Alice<void> > &, int);
friend void Watch<void (*)(), void (*)()>(void (*)(), void (*)(), Movie::Wonderland<Alice<void> > &, int);
friend void Watch<popcorn, void (*)()>(void (*)(), popcorn, Movie::Wonderland<Alice<void> > &, int);
*/
};
//template<class R>
void Watch(Movie::Wonderland< Alice<void> >& theatre, int price)
{
theatre.Attach(new Alice<void>);
int review = theatre->review;
return;
}
template<class F>
void Watch(F func, Movie::Wonderland< Alice<void> >& theatre, int price)
{
theatre.Attach(new Alice<void>);
int review = theatre->review;
return;
}
template<class P, class F>
void Watch(F func, P food, Movie::Wonderland< Alice< void > >& theatre, int price)
{
theatre.Attach(new Alice<void>);
int review = theatre->review;
return;
}
void goWatch(void)
{
return;
}
void eatPopcorn(void)
{
return;
}
struct popcorn
{
};
int main()
{
struct popcorn sweetPopcorn;
Movie::Wonderland< Alice<void> > theatre;
Watch(goWatch, theatre, ONCE);
Watch(goWatch, eatPopcorn, theatre, ONCE);
Watch(theatre, ONCE);
Watch(goWatch, sweetPopcorn, theatre, ONCE);
}
I have reviewed your code, and tested it against two compilers: g++-4.2 and clang++. I do not see any problems regarding your friend declarations.
Why am I getting this error:
Error 1 error C2662: 'Allocator::Allocate' : cannot convert 'this' pointer from 'const Allocator' to 'Allocator &' ?
Thats code:
/*Allocator.h*/
/*Not finished yet but working*/
#pragma once
template<class T>
class Allocator
{
public:
//typedef T value_type;
typedef T* pointer;
pointer Allocate(std::size_t count);
pointer Construct(void* address, const pointer obj);
template<class FwdIter>
void Destroy_(FwdIter first,FwdIter last);
void Deallocate_(void* where);
Allocator();
~Allocator();
private:
void Destroy_(const T* obj);
};
/*Allocator_impl.hpp*/
#pragma once
#include "StdAfx.h"
#include "Allocator.h"
template<class T>
Allocator<T>::Allocator()
{
}
template<class T>
Allocator<T>::~Allocator()
{
/*Destroy();
Deallocate();*/
}
template<class T>
typename Allocator<T>::pointer Allocator<T>::Allocate(std::size_t count)
{
return static_cast<pointer>(::operator new(sizeof(value_type) * count));
}
template<class T>
typename Allocator<T>::pointer Allocator<T>::Construct(void* address, const pointer obj)
{
return new (address) T(*obj);
}
//template<class T>
//void Allocator<T>::Destroy()
//{
// //Destroy_(addressBegin_, addressBegin_ + size_);
//}
template<class T>
void Allocator<T>::Destroy_(const T* obj)
{
obj->~T();
}
template<class T>
template<class FwdIter>
void Allocator<T>::Destroy_(FwdIter first,FwdIter last)
{
while (first != last)
{
Destroy_(&*first);
++first;
}
}
template<class T>
void Allocator<T>::Deallocate_(void* address)
{
::operator delete(address);
}
//template<class T>
//void Allocator<T>::Deallocate()
//{
// //Deallocate_(addressBegin_);
//}
/*Toy.h*/
#pragma once
#include "Allocator_impl.hpp"
/*As a base to managed memory*/
template<class T, class A = Allocator<T>>
class ToyBase
{
typedef T* pointer;
private:
A alloc_;
protected:
//--------------------------------------COMMENT HERE
pointer Allocate(const std::size_t)const;<------------When invoking this fnc from
explicit ToyBase();
virtual ~ToyBase();
};
template<class T, class A>
ToyBase<T,A>::ToyBase()
{}
template<class T, class A>
ToyBase<T,A>::~ToyBase()
{}
//--------------------------------------AND COMMENT HERE
template<class T, class A>
typename ToyBase<T,A>::pointer ToyBase<T,A>::Allocate(const std::size_t count)const
{
return alloc_.Allocate(count);<-----------here
}
/*
But when I remove const from fnc decl. it works. I do not understand it as I do not change an object merely invoke fnc on its member.
*/
template<class T>
class ToyRepresentation : private ToyBase<T>
{
public:
typedef T value_type;
typedef T* pointer;
ToyRepresentation(const std::size_t = 0);
void Push(T*);
void Pop();
void GetSize()const;
void GetCapacity()const;
void SetCapacity(const std::size_t);
void Reset();
private:
pointer data_;
std::size_t size_;
std::size_t capacity_;
static unsigned TOTAL_; //total number of created objects
};
template<class T>
unsigned ToyRepresentation<T>::TOTAL_ = 0;
template<class T>
ToyRepresentation<T>::ToyRepresentation(const std::size_t count = 0): ToyBase<T>(), data_(Allocate(count)), size_(0), capacity_(count)
{
}
/*tmain*/
#include "stdafx.h"
#include "Toy.h"
int _tmain(int argc, _TCHAR* argv[])
{
try
{
ToyRepresentation<int> t;
}
catch(const std::exception&)
{
}
return 0;
}
Comments to interesting lines are marked in code. Thanks.
alloc_.Allocate is not a const method. You can "fix" (or hide) this warning by making alloc_ mutable, although this should not be done without understanding of why the compiler is warning you.
Not sure why the method that calls this needs to be const anyhow. Allocation is not something that typically is expected to leave its context unchanged.
ToyBase<T,A>::Allocate is const qualified which means that you cannot invoke any non-const methods on any members of this as they too are const-qualified now.
Try FAQ 18.10.
how do I provide extra member function for specialized template in a non-inline way?
i.e.
template<typename T>
class sets
{
void insert(const int& key, const T& val);
};
template<>
class sets<bool>
{
void insert(const int& key, const bool& val);
void insert(const int& key){ insert(key, true); };
};
But when I write sets<bool>::insert(const int& key) as
template<>
class sets<bool>
{
void insert(const int& key, const bool& val);
void insert(const int& key);
};
template<>
void sets<bool>::insert(const int& key)
{
insert(key, true);
}
GCC complains:
template-id ‘insert<>’ for ‘void
ip_set::insert(const int&)’ does
not match any template declaration
Besides what Effo said, if you want to add additional functionality in specializations you should move common functionality into a base template class. E.g.:
template<typename T>
class Base
{
public:
void insert(const int& key, const T& val)
{ map_.insert(std::make_pair(key, val)); }
private:
std::map<int, T> map_;
};
template<typename T>
class Wrapper : public Base<T> {};
template<>
class Wrapper<bool> : public Base<bool>
{
public:
using Base<bool>::insert;
void insert(const int& key);
};
void Wrapper<bool>::insert(const int& key)
{ insert(key, true); }
That's because it is not a function of your template so don't use "template<>". It works for me after removing "template<>" as below:
void sets<bool>::insert(const int& key)
{
insert(key, true);
}
My system FC9 x86_64.
The entire code:
template<typename T>
class sets
{
public:
void insert(const int& key, const T& val);
};
template<>
class sets<bool>
{
public:
void insert(const int& key, const bool& val) {}
void insert(const int& key);
};
void sets<bool>::insert(const int& key)
{
insert(key, true);
}
int main(int argc, char **argv)
{
sets<bool> ip_sets;
int key = 10;
ip_sets.insert(key);
return 0;
}
i think you should understand the following two points :
if the you want to specilize the class primary template, you must put the 'template<>' before the specilized edition declaration.but as for the member function, you needn't put the 'template<...>' before the member function definition(because the type info of the specilized template class has been set by you).
i don't think the primary template class has ant thing to do with the specilized edition.