Reputation: 591
I've written a template class
template<typename T, typename U>
class ANotifier : public ACancelable
{
public:
virtual std::weak_ptr<ACancelableToken> RegisterNotification( U msgType, std::function<void(T&)> fn ) = 0;
virtual void Notify( U msgType, T& value ) = 0;
};
template<typename T, typename U>
class ASingleNotifier : public ANotifier<T, U>
{
...
}
template<typename T, typename U>
class AMultiNotifier : public ANotifier<T, U>
{
...
}
The base class provides a function signature in the lambda. I'm having to repeatedly define the function signature everytime I implement the function or want to make a stack variable of the specific function signature.
I was wondering if there is a way to create a typedef
So something like this
template<typename T, typename U>
class ANotifier : public ACancelable
{
public:
typedef std::function<void(T&)> NotificationFn
virtual std::weak_ptr<ACancelableToken> RegisterNotification( U msgType, NotificationFn fn ) = 0;
virtual void Notify( U msgType, T& value ) = 0;
};
template<typename T, typename U>
class ASingleNotifier : public ANotifier<T, U>
{
...
virtual std::weak_ptr<ACancelableToke> RegisterNotification( U msgType, NotificationFn fn );
}
template<typename T, typename U>
class AMultiNotifier : public ANotifier<T, U>
{
...
virtual std::weak_ptr<ACancelableToke> RegisterNotification( U msgType, NotificationFn fn );
}
Do I need to declare a typedef in each template subclass. Also when actually creating a stack variable to a function of a specific type how would I declare the fn. eg. NotificationFn<uint32_t> fn;
I used what I have above and I get this error:
/Users/kartik/Projects/pancam/hardware/neolib/inc/ANotifier.h:36:76: error: unknown type name 'NotificationFnOld' virtual std::weak_ptr RegisterNotification( U msgType, NotificationFnOld fn )
where NotificationFnOld
is the same as NotificationFn
What I want to do is be able to change the function signature in one place (ie add/rem params) and have it bound to the typedef. I don't mind declaring new typedefs in each subclass as long as I can just have one place to change the signature (ofcourse I will have to change the function implementations but I would like to avoid having to modify intermediate variables and stuff).
EDIT
I modified the typedef to a using
and still got a similar error. This is what I used...
Instead of typedef std::function<void(T&)> NotificationFn;
I used using NotificationFnOld = std::function<void( T& )>;
And this is the error I got.
/Users/kartik/Projects/pancam/hardware/neolib/inc/ANotifier.h:36:76: error: unknown type name 'NotificationFnOld' virtual std::weak_ptr RegisterNotification( U msgType, NotificationFnOld fn )
The error is reported on the Subclass ASingleNotifier
in the prototype of overriden function RegisterNotification
. It doesn't complain when the alias is used in the prototype declared in ANotifier
. How do I cleanly use the alias in my subclasses ?
NOTE: NotificationFnOld
and NotificationFn
are used interchangeably in this question, I actually use only NotificationFnOld
in my code.
EDIT
Incase details are needed, here is the code of what I'm trying.
There should be no relation with ACancelable
but if more info is needed I will provide.
template<typename T, typename U>
class ANotifier : public ACancelable
{
public:
using NotificationFn = std::function<void( T&, std::weak_ptr<ACancelableToken> )>;
using NotificationFnOld = std::function<void( T& )>;
virtual std::weak_ptr<ACancelableToken> RegisterNotification( U msgType, std::function<void( T&, std::shared_ptr<ACancelableToken> )> fn ) = 0;
virtual void Notify( U msgType, T& value ) = 0;
};
template<typename T, typename U>
class ASingleNotifier : public ANotifier<T, U>
{
public:
virtual ~ASingleNotifier()
{ }
virtual std::weak_ptr<ACancelableToken> RegisterNotification( U msgType, std::function<void( T&, std::shared_ptr<ACancelableToken> )> fn )
{
std::weak_ptr<ACancelableToken> retval;
std::unique_lock <std::mutex> lk( m_mtx );
std::shared_ptr <ATypedCancelableToken<U>> tmp( std::make_shared<ATypedCancelableToken<U>>( *this, msgType ));
if( m_notifierMap.find( msgType ) == m_notifierMap.end() ) {
m_notifierMap[ msgType ] = std::make_pair( fn, tmp );
retval = tmp;
}
return retval;
}
virtual void CancelWith( std::shared_ptr<ACancelableToken> spBaseToken ) const
{
try {
auto spToken = std::dynamic_pointer_cast<ATypedCancelableToken<U>>( spBaseToken );
std::unique_lock<std::mutex> lk( this->m_mtx );
m_notifierMap.erase( spToken->m_msgType );
}
catch ( std::bad_cast exp ) { }
}
virtual void Notify( U msgType, T& value )
{
m_mtx.lock();
auto it = m_notifierMap.find( msgType );
if ( it != m_notifierMap.end() && it->second.first ) {
auto fn = it->second.first;
m_mtx.unlock();
fn( value );
}else {
m_mtx.unlock();
}
}
protected:
mutable std::map <U, std::pair<std::function<void( T&, std::shared_ptr<ACancelableToken> )>, std::shared_ptr<ATypedCancelableToken<U>>>> m_notifierMap;
mutable std::mutex m_mtx;
};
template<typename T, typename U>
class AMultiNotifier : public ANotifier<T,U>
{
protected:
class AmnCancellableToken : public ATypedCancelableToken<U>
{
public:
AmnCancellableToken( const ACancelable& cancellable,
U msgType,
typename std::list<std::pair<std::function<void( T&, std::shared_ptr<ACancelableToken> )>,std::shared_ptr<AmnCancellableToken>>>::iterator it ) :
ATypedCancelableToken<U>{ cancellable, msgType }, m_it{ it } { }
~AmnCancellableToken() {}
const typename std::list<std::pair<std::function<void( T&, std::shared_ptr<ACancelableToken> )>,std::shared_ptr<AmnCancellableToken>>>::iterator m_it;
};
public:
~AMultiNotifier() { }
virtual std::weak_ptr<ACancelableToken> RegisterNotification( U msgType, std::function<void( T&, std::shared_ptr<ACancelableToken> )> fn )
{
std::weak_ptr<ACancelableToken> retval;
std::unique_lock <std::mutex> lk( m_mtx );
std::shared_ptr<AmnCancellableToken> token;
m_notifierMap[ msgType ].push_back( std::make_pair( fn, token) );
auto it = m_notifierMap[msgType].end();
token = std::make_shared<AmnCancellableToken>( *this, msgType, --it );
m_notifierMap[ msgType ].back().second = token;
retval = token;
return retval;
}
virtual void CancelWith( std::shared_ptr<ACancelableToken> spBaseToken ) const
{
try {
auto spToken = std::dynamic_pointer_cast<AmnCancellableToken>( spBaseToken );
std::unique_lock<std::mutex> lk( this->m_mtx );
if ( !m_notifierMap[ spToken->m_msgType ].empty()) { //If the list of handler is not empty
m_notifierMap[ spToken->m_msgType ].erase( spToken->m_it ); //Delete the handler in list
if ( m_notifierMap[ spToken->m_msgType ].empty()) //If the list is now empty
m_notifierMap.erase( spToken->m_msgType ); // Delete the msgType Key element
}
} catch ( std::bad_cast exp ) { }
}
virtual void Notify( U msgType, T& value )
{
m_mtx.lock();
auto anotherCopy = m_notifierMap;
m_mtx.unlock();
typename std::map<U, std::list<std::pair<std::function<void( T&, std::shared_ptr<ACancelableToken> )>, std::shared_ptr<AmnCancellableToken>>>>::iterator ait =
anotherCopy.find( msgType );
if( ait != anotherCopy.end() &&
!ait->second.empty() ) {
for( auto ait2 = ait->second.begin(); ait2 != ait->second.end(); ait2++ )
if( ait2->first )
ait2->first( value );
}
}
protected:
mutable std::map <U, std::list<std::pair<std::function<void( T&, std::shared_ptr<ACancelableToken> )>,std::shared_ptr<AmnCancellableToken>>>> m_notifierMap;
mutable std::mutex m_mtx;
};
Thanks for the help / suggestions
Kartik
Upvotes: 0
Views: 559
Reputation: 24249
You need to qualify NotificationFn:
virtual std::weak_ptr<ACancelableToken> RegisterNotification( U msgType, typename ANotifier<T,U>::NotificationFn fn );
Or if you are going to be using it multiple times, add a using statement:
using NotificationFn = typename ANotifier<T,U>::NotificationFn;
inside each derived class.
here's a complete example:
#include <iostream>
#include <functional>
#include <memory>
struct ACancelable {};
struct ACancelableToken {};
template<typename T, typename U>
class ANotifier : public ACancelable
{
public:
using NotificationFn = std::function<void(T&)>;
virtual std::weak_ptr<ACancelableToken> RegisterNotification( U msgType, NotificationFn fn ) = 0;
virtual void Notify( U msgType, T& value ) = 0;
};
template<typename T, typename U>
class ASingleNotifier : public ANotifier<T, U>
{
virtual std::weak_ptr<ACancelableToken> RegisterNotification( U msgType, typename ANotifier<T,U>::NotificationFn fn );
};
int main() {
// your code goes here
return 0;
}
Upvotes: 1