My C++ is a little rusty having worked in Java and C# for the last half dozen years. I've got a stupid little error that I just cannot figure out.
I've pared the code down as much as possible.
#include <list>
template<class T> class Subscriber
{
virtual void published( T t ) = 0;
};
template <class T> class PubSub
{
private:
std::list< Subscriber<T>* > subscribers;
public:
void publish( T t );
};
template<class T> void PubSub<T>::publish( T t )
{
for( std::list< Subscriber<T>* >::iterator i = subscribers.begin(); i != subscribers.end(); ++i )
i->published( t );
}
When I try and compile this (by including this header file in a code file), I get the following error:
../util/pubsub.h: In member function ‘void PubSub<T>::publish(T)’:
../util/pubsub.h:18: error: expected `;' before ‘i’
../util/pubsub.h:18: error: ‘i’ was not declared in this scope
What am I missing here?
for( typename std::list< Subscriber<T>* >::iterator i = ...
^^^^^^^^
for( typename std::list< Subscriber<T>* >::iterator i = subscribers.begin(); i != subscribers.end(); ++i )
You need the typename because iterator is a dependent name. The compiler has to check the template type T before it knows whether iterator is a type or a value. In those cases, it assumes it to be a value, unless you add typename.
This
std::list< Subscriber<T>* >::iterator
needs to be this
typename std::list< Subscriber<T>* >::iterator
The compiler assumes nested names in templates are static variables (not types) until told otherwise.
Related
I am trying to use multi_index_container with templates. below is my code.
template < class ValueType >
class anrQueue
{
private:
typedef boost::multi_index_container<
ValueType,
indexed_by<
sequenced<>,
ordered_unique<identity<ValueType> >
>
> a_queue;
a_queue mQueue;
public:
size_t remove(const ValueType& x) {
return mQueue.get<1>().erase(x);
}
-------------------------^
error: expected primary-expression before ‘)’ token
How to resolve this
Write:
return mQueue.template get<1>().erase(x);
Look here for an explanation on the usage of template on dependent contexts.
I want to write something to share memory,
pAttr is the share memory address.
The template function as below,
but it does not pass the compile.
template <typename Container>
int ShareMemMgn::writeContainerToShareMemMap(void* pAttr, Container& oData)
{
typename Container::mapped_type T;
(T*)(pElem) = (T *)(pAttr); //compile errror
/*
share_mem_mgn.cpp:545: error: expected primary-expression before ‘)’ token
share_mem_mgn.cpp:545: error: ‘pElem’ was not declared in this scope
share_mem_mgn.cpp:545: error: expected primary-expression before ‘)’ token
*/
for(typename Container::iterator it = oData.begin();
it != oData.end(); ++it)
{
memcpy(pElem, (&(it->second)), sizeof(typename Container::mapped_type));
++pElem;
}
return 0;
}
How to get the maped type pointer?
Could anyone help me?
Thanks a lot.
As your code reads right now, T is a variable, not a type. Presumably you meant this:
typedef typename Container::mapped_type T;
T * pElem = static_cast<T *>(pAttr);
You could also do this
template <typename KeyType, typename ValueType>
int ShareMemMgn::writeContainerToShareMemMap(void* pAttr, std::map<KeyType,ValueType>& oData)
If you are using only a Map.
Why isn't this code compiling ?
#include <cstdlib>
#include <list>
template < typename Type >
class Allocator {
public:
using value_type = Type;
public:
template < typename Other >
struct rebind { using other = Allocator< Other >; };
public:
Type * allocate( std::size_t n ) { return std::malloc( n ); }
void deallocate( Type * p, std::size_t ) throw ( ) { std::free( p ); }
};
int main( void ) {
std::list< void *, Allocator< void * > > list;
return 0;
}
It seems to need pointer, reference, pointer_const & reference_const types. However, according to cppreference these members are all optionals. It seems like if the STL weren't using allocator_trait (I'm compiling with -std=c++11 so it should be good).
Any idea ?
[edit] On clang, errors are :
user#/tmp > clang++ -std=c++11 test.cc
In file included from test.cc:2:
In file included from /usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/list:63:
/usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/stl_list.h:449:40: error: no type named 'pointer' in 'Allocator<void *>'
typedef typename _Tp_alloc_type::pointer pointer;
~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
test.cc:17:46: note: in instantiation of template class 'std::list<void *, Allocator<void *> >' requested here
std::list< void *, Allocator< void * > > list;
^
In file included from test.cc:2:
In file included from /usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/list:63:
/usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/stl_list.h:450:40: error: no type named 'const_pointer' in 'Allocator<void *>'
typedef typename _Tp_alloc_type::const_pointer const_pointer;
~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
/usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/stl_list.h:451:40: error: no type named 'reference' in 'Allocator<void *>'
typedef typename _Tp_alloc_type::reference reference;
~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
/usr/lib/gcc/i686-pc-linux-gnu/4.7.1/../../../../include/c++/4.7.1/bits/stl_list.h:452:40: error: no type named 'const_reference' in 'Allocator<void *>'
typedef typename _Tp_alloc_type::const_reference const_reference;
~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
4 errors generated.
This is a bug in GCC's C++ standard library.
When using a list, they are not properly wrapping access to the allocator through an allocator_traits.
However, they do implement vector correctly. This code would compile if you used std::vector instead of std::list.
I'm trying to port a project from Windows to Mac. I'm having troubles compiling the class CFactory. I'll try to illustrate the problem.
Here's what I have on my Factory.h
namespace BaseSubsystems
{
template <class T>
class CFactory
{
protected:
typedef T (*FunctionPointer)();
typedef std::pair<std::string,FunctionPointer> TStringFunctionPointerPair;
typedef std::map<std::string,FunctionPointer> TFunctionPointerMap;
TFunctionPointerMap _table;
public:
CFactory () {}
virtual ~CFactory();
}; // class CFactory
template <class T>
inline CFactory<T>::~CFactory()
{
TFunctionPointerMap::const_iterator it = _table.begin();
TFunctionPointerMap::const_iterator it2;
while( it != _table.end() )
{
it2 = it;
it++;
_table.erase(it2);
}
} // ~CFactory
}
When I'm trying to compile, the compiler complains:
Factory.h:95:44: error: expected ';' after expression [1]
TFunctionPointerMap::const_iterator it = _table.begin();
^
;
Why is this happening? That am I missing?
NOTE: This project compiles properly on MSVC.
Thanks.
You are missing the required typename keyword when referring to a dependent type. Microsoft Visual Studio incorrectly accepts your code without the typename (this is a well known mistake in VS that will never be corrected).
typename TFunctionPointerMap::const_iterator it;
How is one supposed to use a std container's value_type?
I tried to use it like so:
#include <vector>
using namespace std;
template <typename T>
class TSContainer {
private:
T container;
public:
void push(T::value_type& item)
{
container.push_back(item);
}
T::value_type pop()
{
T::value_type item = container.pop_front();
return item;
}
};
int main()
{
int i = 1;
TSContainer<vector<int> > tsc;
tsc.push(i);
int v = tsc.pop();
}
But this results in:
prog.cpp:10: error: ‘T::value_type’ is not a type
prog.cpp:14: error: type ‘T’ is not derived from type ‘TSContainer<T>’
prog.cpp:14: error: expected ‘;’ before ‘pop’
prog.cpp:19: error: expected `;' before ‘}’ token
prog.cpp: In function ‘int main()’:
prog.cpp:25: error: ‘class TSContainer<std::vector<int, std::allocator<int> > >’ has no member named ‘pop’
prog.cpp:25: warning: unused variable ‘v’
I thought this was what ::value_type was for?
You have to use typename:
typename T::value_type pop()
and so on.
The reason is that the compiler cannot know whether T::value_type is a type of a member variable (nobody hinders you from defining a type struct X { int value_type; }; and pass that to the template). However without that function, the code could not be parsed (because the meaning of constructs changes depending on whether some identifier designates a type or a variable, e.g.T * p may be a multiplication or a pointer declaration). Therefore the rule is that everything which might be either type or variable and is not explicitly marked as type by prefixing it with typename is considered a variable.
Use the typename keyword to indicate that it's really a type.
void push(typename T::value_type& item)
typename T::value_type pop()
Here is a full implementation of the accepted answers above, in case it helps anyone.
#include <iostream>
#include <list>
template <typename T>
class C1 {
private:
T container;
typedef typename T::value_type CT;
public:
void push(CT& item) {
container.push_back(item);
}
CT pop (void) {
CT item = container.front();
container.pop_front();
return item;
}
};
int main() {
int i = 1;
C1<std::list<int> > c;
c.push(i);
std::cout << c.pop() << std::endl;
}
A fairly common practice is to provide an alias representing the underlying value type for convenience.
template <typename T>
class TSContainer {
private:
T container;
public:
using value_type = typename T::value_type;
void push(value_type& item)
{
container.push_back(item);
}
value_type pop()
{
value_type item = container.pop_front();
return item;
}
};