C++ Template specialization to provide extra member function? - c++

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.

Related

Provide public specialization of protected template member function

I'd like to do the following:
class Foo {
protected:
template<Param>
void operator()(const Param& param) {
// stuff involving some RTTI magic
}
public:
void operator()(const A& param) should be operator()<A>;
void operator()(const B& param) should be operator()<B>;
}
Basically, I have a generic operator() that takes a generic template parameter. But, I only want to publish specific specializations for type safety.
Thanks!
Just give the private function a different name:
class Foo
{
private:
template <typename T> void foo(const T &);
public:
void operator()(const A & x) { foo(x); }
void operator()(const B & x) { foo(x); }
};

How to declare an object of nested class present in base class

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;
// ~~~~~~~^ ~~~~~~~~^
}

Can a Specialized Template Class Inherit from Another Specialized Template Class?

I first defined
class Hash
{
};
Then a specialization of Hash.
template <class T>
class Hash<int, T>
{
public:
Hash(int slotN = 11);
bool insert(int key, T val);
bool remove(int key);
bool contains(int key);
bool query(int key, T& val) ;
protected:
// Basic Variables of the Hash Model.
list<int>* slot;
list<T>* slotVal;
int slotN;
};
I want to use this specialized version of Hash
to implement another specialization: Hash of
String-Valued Keys.
template <class T>
class Hash<string, T> : public Hash<int, T>
{
public:
Hash(int slotN);
bool insert(string key, T val);
bool remove(string key);
bool contains(string key);
bool query(string key, T& val) ;
private:
// Calculate the String's Hash Key.
int str2key( string key);
};
But it seemed I cannot access fields in the class Hash. Why?
When you say "I cannot access fields in the class Hash" I guess you mean, that you when you are using Hash<string, T> (for some type T) that you cannot call the overloaded functions from Hash<int, T>. The reason for this is name hiding: when you overload a member function in a derived class, all members with the same name in the base class are hidden unless you make them explicitly available. The way to do it is a using declaration:
template <class T>
class Hash<string, T> : public Hash<int, T>
{
public:
Hash(int slotN);
using Hash<int, T>::insert;
using Hash<int, T>::remove;
using Hash<int, T>::contains;
using Hash<int, T>::query;
bool insert(string key, T val);
bool remove(string key);
bool contains(string key);
bool query(string key, T& val) ;
private:
// Calculate the String's Hash Key.
int str2key( string key);
};
If you just need to access the base class members from your derived class's implementation, you can also access the names using qualification with the class name. For example:
template <typename T>
bool Hash<string, T>::insert(string key, T val) {
return this->Hash<int, T>::insert(this->str2key(key, val);
}
Thinking a bit more about the question, there is another potential issue: If you access the data members in the base class you need to make sure that the compiler considers the name a dependent name. Otherwise it is looked up in phase one and won't the names in the base because the can only be found in phase two:
template <typename T>
bool Hash<string, T>::insert(string key, T val) {
int n0 = slotN; // doesn't work: looked up in phase 1
int n1 = this->slotN; // OK: name is dependent
int n2 = Hash<int, T>::slotN; // OK, too
}
Personally, I wouldn't publicly derive from a class with a different key but I assume you have your reasons. BTW, I assume that your primary declaration of Hash looks something like this although it doesn't matter for the problem, really:
template <typename K, typename T>
class Hash;
(if it doesn't have any members, I would rather not define it, either).

Why does this code compile? (C++ template question)

I am writing a generalized container using a class template, with a restriction (policy) that the items stored in the container should derive from a specific base class.
Here is the definition of the class template
// GenericContainer.hpp
// --------------------------------------
class ContainerItem
{
protected:
virtual ContainerItem& getInvalid() = 0;
public:
virtual ~ContainerItem();
bool isValid() const;
};
template<typename D, typename B>
class IsDerivedFrom
{
static void Constraints(D* p)
{
B* pb = p; // this line only works if 'D' inherits 'B'
pb = p; // suppress warnings about unused variables
}
protected:
void IsDerivedFrom2() { void(*p)(D*) = Constraints; }
};
// Force it to fail in the case where B is void
template<typename D>
class IsDerivedFrom<D, void>
{
void IsDerivedFrom2() { char* p = (int*)0; /* error */ }
};
template <class T>
class GenericContainer : public IsDerivedFrom<T, ContainerItem>
{
private:
typedef std::vector<T> TypeVect;
void addElement(const T& elem);
TypeVect m_elems;
public:
unsigned int size() const;
T& elementAt(const unsigned int pos);
const T& elementAt(const unsigned int pos) const;
};
template <class T>
void GenericContainer<T>::addElement(const T& elem)
{
m_elems.push_back(elem);
}
template <class T>
unsigned int GenericContainer<T>::size() const
{
return m_elems.size();
}
template <class T>
T& GenericContainer<T>::elementAt(const unsigned int pos)
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
template <class T>
const T& GenericContainer<T>::elementAt(const unsigned int pos) const
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
// Class to be contained (PURPOSELY, does not derive from ContainerItem)
// Data.hpp
//----------------------------------------------------------------
class Data
{ /* implem details */};
// Container for Data items
// Dataset.h
// ----------------------------------------------------------------------------
#include "GenericContainer.hpp"
#include "Data.hpp"
class Dataset: public GenericContainer<Data>
{
public:
Data& getInvalid();
};
// C++ source
// -----------------------------------------------------------
#include "Dataset.hpp"
Dataset ds;
Can anyone explain why the code above compiles?.
[Edit]
The code above should NOT compile for two reasons:
The class 'Data' does NOT derive from ContainerItem, and yet it can be stored in GenericContainer (as illustrated by the class Dataset). Incidentally, this issue has now been resolved thanks to the answer given by Omifarious and jdv
The class 'Data' does NOT implement the pure virtual method declared in the ABC ContainerItem - using the fixes recommended in the answers below, the first issue (enforcement of policy) is resolved, however the compiler fails to notice that Data does not implement the getInvalid() method of the ContainerItem 'interface'. Why is the compiler missing this glaring mistake?
BTW, compiler and OS details are:
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Change IsDerivedFrom2 to IsDerivedFrom and it fails to compile in just the expected manner.
The problem is that a method from a template class is never instantiated if it isn't called. Changing the name makes it a constructor, so it then ends up being called by the constructors of classes derived from IsDerivedFrom. It will still compile to empty code. The compiler will optimize it away the dead assignment.
I would recommend you not write template code like this yourself if you can manage to use Boost, particularly is_base_of from the Boost type traits library.
In particular, your GenericContainer template can be more simply and easily implemented this way using Boost:
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_base_of.hpp>
template <class T>
class GenericContainer
{
private:
typedef std::vector<T> TypeVect;
void addElement(const T& elem);
TypeVect m_elems;
public:
unsigned int size() const;
T& elementAt(const unsigned int pos);
const T& elementAt(const unsigned int pos) const;
GenericContainer() {
BOOST_STATIC_ASSERT( (::boost::is_base_of<ContainerItem, T>::value) );
}
};
template <class T>
void GenericContainer<T>::addElement(const T& elem)
{
m_elems.push_back(elem);
}
template <class T>
unsigned int GenericContainer<T>::size() const
{
return m_elems.size();
}
template <class T>
T& GenericContainer<T>::elementAt(const unsigned int pos)
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
template <class T>
const T& GenericContainer<T>::elementAt(const unsigned int pos) const
{
unsigned int maxpos = m_elems.size();
if (pos < maxpos)
return m_elems[pos];
return T::getInvalid();
}
The Constraints function is not generated because IsDerivedFrom2 is never referenced. This is required behavior for C++. Maybe it helps to call it from the constructor. Otherwise, check the boost library for functionality like this.

When I need to specialize the typename I declared in my template class, what arguments I must use?

I have a template class for thread-safe vector:
template <class T>
class SharedVector {
std::vector<T> vect;
CRITICAL_SECTION cs;
SharedVector(const SharedVector<T>& rhs) {}
public:
typedef typename std::vector<T>::size_type SizeType;
SharedVector();
void PushBack(const T& value);
void PopBack();
SizeType size();
const T& operator[](int index);
void erase(int index);
void Lock();
void Unlock();
virtual ~SharedVector();
};
Then I want to use it in my client manager for TCP server to delegate some
responsibilities from client manager to this vector:
class TCPClientManager {
TCPClientManager(const TCPClientManager&) {}
TCPClientManager& operator=(const TCPClientManager&) {}
SharedVector<Connection*> connections;
public:
TCPClientManager();
SharedVector<>::SizeType size(); //here is the problem
void addConnection(const Client&);
void breakConnection(int);
void deleteConnection(int);
void Lock();
void Unlock();
~TCPClientManager();
};
typename SharedVector<>::SizeType TCPClientManager::size() {
return connections.size();
}
I need to declare the type of retrieving value. Compiler said that it was too few arguments for template.
You have to provide a type argument for the SharedVector template:
SharedVector<Connection*>::SizeType size();
....
SharedVector<Connection*>::SizeType TCPClientManager::size() {
return connections.size();
}
Because that Connection* type is not a template parameter in TCPClientManager, but an explicit chosen type, you don't need to put typename before SharedVector<Connection*>::SizeType
(In addition to litb, really)
You should typedef your container; i.e. typedef SharedVector<Connection*> ConnectionPool;. This would allow you to write ConnectionPool::size_type.
Note: container::size() should return a container::size_type, not container::SizeType. This makes the container STL-compatible. For the same reason, the iterator class should be container::iterator, adding elements is done by container::push_back(container::value_type const&), etc.