I moved out the methods implementation from my class and caught the following error:
use of class template requires template argument list
for method whitch doesn't require template type at all... (for other methods all ok)
Class
template<class T>
class MutableQueue
{
public:
bool empty() const;
const T& front() const;
void push(const T& element);
T pop();
private:
queue<T> queue;
mutable boost::mutex mutex;
boost::condition condition;
};
Wrong implementation
template<> //template<class T> also incorrect
bool MutableQueue::empty() const
{
scoped_lock lock(mutex);
return queue.empty();
}
It should be:
template<class T>
bool MutableQueue<T>::empty() const
{
scoped_lock lock(mutex);
return queue.empty();
}
And if your code is that short, just inline it, as you can't separate the implementation and header of a template class anyway.
Use:
template<class T>
bool MutableQueue<T>::empty() const
{
...
}
Related
I need a 'MultiStack' taking different types of objects, putting each type in a separate stack.
This is what it looks like so far. The open problem is: how to handle the containers for a number of different T
class MultiStack
{
public:
template<typename T>
const T& Get()
{
return Container<T>.back();
}
template<typename T>
void Push( const T& t )
{
Container<T>.push_back( t );
}
template<typename T>
void Pop( const T& /*t*/ )
{
Container<T>.pop_back();
}
private:
// this does not make sense, we obv. need one stack for each T
// template<typename T>
// std::vector<T> Container;
};
Now, I could use the old trick, putting the Container in a member function, like
template<typename T>
auto GetContainer()
{
static std::vector<T> C;
return C;
}
but I don't like this anymore in the age of multi-threading. It is 'dangerous', right!?
Is there a better, elegant way? It is conceivable that I know the allowed types beforehand, if that helps realizing it.
but I don't like this anymore in the age of multi-threading. It is 'dangerous', right!?
Issue is not multi-threading. initialization would be fine.
You still have to protect/synchronize access though, as regular multi-threading code.
Issue is that the container is not per instance of MultiTask, as it is static.
It is mostly as if MultiTask were a Singleton.
It is conceivable that I know the allowed types beforehand, if that helps realizing it.
That helps, you can then use std::tuple, something like (C++14):
template <typename ... Ts>
class MultiStack
{
public:
template<typename T>
const T& Get() const
{
return GetContainer<T>().back();
}
template<typename T>
void Push(const T& t)
{
GetContainer<T>().push_back(t);
}
template <typename T>
void Pop()
{
GetContainer<T>().pop_back();
}
private:
template <typename T>
const std::vector<T>& GetContainer() const { return std::get<std::vector<T>>(Containers); }
template <typename T>
std::vector<T>& GetContainer() { return std::get<std::vector<T>>(Containers); }
private:
std::tuple<std::vector<Ts>...> Containers;
};
OK I have this code:
// default implementation just uses a mutex to serialize access
template <typename T, typename=void>
struct kernport {
static const bool atomic = false;
// constructor
kernport(T value=T()) {
set(value);
}
// get/set value
T get() const { std::unique_lock<std::mutex> lock(lock_); return value_; }
void set(const T& value) { std::unique_lock<std::mutex> lock(lock_); value_ = value; }
private:
mutable std::mutex lock_;
T value_;
};
// specialization if std::atomic<T> exists
template <typename T>
struct kernport<T, void_type<decltype(std::atomic<T>())>> {
static const bool atomic = true;
// constructor
kernport(T value=T()) {
set(value);
}
// query port value
T get() const { return value_.load(std::memory_order_acquire); }
void set(const T& value) { value_.store(value, std::memory_order_release); }
private:
std::atomic<T> value_;
};
If I try to check kernport<bool>::atomic, I get the dreaded undefined reference. OK, so I need to define the member outside of the class:
template <typename T> const bool kernport<T>::atomic;
Unfortunately, doing that, I get:
inc/skunk/dataflow/kernel.h:472:47: error: template definition of
non-template ‘const bool sk::kernport::atomic’ template const bool kernport::atomic;
And for the life of me I can find the right syntax. How do I write this?
Maybe
template <typename T1, typename T2>
const bool kernport<T1, T2>::atomic;
template <typename T1>
const bool kernport<T1, void>::atomic;
?
Don't forget the second (defaulted to void) template parameter.
Given this example class template:
template<typename T>
class Stack {
T * data;
int size;
int nextIndex;
public:
Stack(int size = 100);
Stack(const Stack& stack);
~Stack();
Stack& operator=(const Stack& s);
void push(const T& t);
void pop();
T& top();
const T& top() const;
int getSize() const;
class Full {
};
class Empty {
};
};
template<typename T>
void Stack::push(const T& t) {
if (nextIndex >= size) {
throw Full();
}
data[nextIndex++] = t;
}
template<typename T>
void Stack::pop() {
if (nextIndex <= 0) {
throw Empty();
}
nextIndex--;
}
Is it ok the part of the implementaion of the push and pop methods?
I don't understand if I need to write void Stack<T>::push(const T& t) instead of void Stack::push(const T& t) (and the same for the pop method).
NOTE: Eclipse (according to C++11) gives me the next error:
Member declaration not found
because of these lines:
void Stack::push(const T& t) {
void Stack::pop() {
The part of the implementaion of push method and pop method it's ok? I don't understand if I need to write void Stack::push(const T& t) instead void Stack::push(const T& t) (and the same for pop method).
You need to use
template <typename T>
void Stack<T>::push(const T& t) { ... }
template <typename T>
void Stack<T>::pop() { ... }
The name Stack is the same as Stack<T> inside the class template definition when it is used as a typename. Outside the class template definition, you have to supply the template parameter explicitly.
Both push() and pop() are (non-template) member functions of the Stack class template. Since this class template, Stack, is parameterized by a type template parameter (i.e.: T), so are those member functions as well.
Therefore, the implementation of those member functions needs a type template parameter:
template<typename A>
void Stack<A>::push(const A& t) { ... }
template<typename B>
void Stack<B>::pop() { ... }
Note that the name of the template parameter is actually irrelevant (A and B above).
Note as well that the name of the class template Stack not followed by any template arguments inside the body of its definition is equivalent to the class template with its template parameter as the template argument, i.e.: Stack<T>.
I've declared a template class MyContainer as bellow, then created an instance of it of type DataType1. The DataType1 class provides a friend function "DataSpecificComparison" which is used by std::sort to compare DataType1 objects. The program compiled and sorted correctly.
I then defined a class called DataType2, gave it a friend implementation of "DataSpecificComparison" and used it to create another instance of MyContainer.
I am now unable to compile the program as a "C2914: 'std::sort' : cannot deduce template argument as function argument is ambiguous" compile time error is reported.
How can a developer specify that the DataSpecificComparison binary predicate is to take arguments of template type T*? Or is there another way around this issue?
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
....
public:
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison)
}
}
class DataType1
{
....
friend bool DataSpecificComparison(const DataType1 * lhs, const DataType1 * rhs)
}
class DataType2
{
....
friend bool DataSpecificComparison(const DataType2* lhs, const DataType2* rhs)
}
You can use a temporary local function pointer variable of the required type to select the correct overload of DataSpecificComparison:
void SortMyContainerObjects()
{
typedef bool (*comparer_t)(const T*, const T*);
comparer_t cmp = &DataSpecificComparison;
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), cmp);
}
Here the compiler can deduce that you want to use the DataSpecificComparison overload that matches the comparer_t type, which resolves the ambiguity.
sth already gave a correct answer, but there's also a direct alternative based on the same principle:
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(),
static_cast<bool (*comparer_t)(const T*, const T*)>(&DataSpecificComparison));
}
This uses essentially the same mechanism. The cast forces overload resolution to happen before the Template Argument Deduction for std::sort.
template<typename T>
struct DataSpecificComp : public binary_function<T, T, bool>
{
public:
bool operator()(const T* lhs, const T* rhs)
{
return *lhs < *rhs;
}
};
call the sort function as shown below:
sort(vi.begin(), vi.end(), DataSpecificComp<int>());
I'd prefer something along the following lines: by default it compares objects with less_than (so you wouldn't have to remember to provide a function with a funny name), and there's an overload that allows giving your own comparison functor (again, value-based):
#include <vector>
#include <algorithm>
#include <functional>
template <class T, class Func>
struct indirect_binary_call_type: public std::binary_function<const T*, const T*, bool>
{
Func f;
indirect_binary_call_type(Func f): f(f) {}
bool operator()(const T* a, const T* b) const
{
return f(*a, *b);
}
};
template <class T, class Func>
indirect_binary_call_type<T, Func> indirect_binary_call(Func f)
{
return indirect_binary_call_type<T, Func>(f);
}
template <class T>
class MyContainer
{
private:
std::vector<T*> m_vMyContainerObjects;
public:
void Sort()
{
Sort(std::less<T>());
}
template <class Func>
void Sort(Func f )
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), indirect_binary_call<T>(f));
}
};
int main()
{
MyContainer<int> m;
m.Sort();
m.Sort(std::greater<int>());
}
Did you try defining DataSpecificComparison as template with bunch of specializations and giving it the type?
template<T>
bool DataSpecificComparison(const T* t1, const T* t2)
{
// something non compilable here
}
template<> bool DataSpecificComparison<Data1>(const Data1* t1, const Data1* t2)
{
// return *t1 < *t2;
}
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison<T>)
}
....
Templating DataSpecificComparison should work. You can also specifically call the proper std::sort template, but it's a bit cumbersome:
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
typedef bool (*compsT)(T, T);
public:
....
void SortMyContainerObjects()
{
std::sort<std::vector<T*>::iterator, compsT>(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison);
}
}
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.