ich eine Template-Klasse geschrieben habeWie eine Funktion Signatur für eine Methode in einer Template-Klasse typedef wobei die Parameter ein generischer Typ ist
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>
{
...
}
Die Basisklasse eine Funktion Signatur im Lambda liefert. Ich muss die Funktionssignatur immer neu definieren, wenn ich die Funktion implementiere oder eine Stapelvariable der spezifischen Funktionssignatur machen möchte.
Ich habe mich gefragt, ob es einen Weg gibt, eine typedef
So etwas wie diese
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);
}
Habe ich eine typedef in jeder Vorlage Unterklasse deklarieren müssen zu erstellen. Wenn ich tatsächlich eine Stapelvariable zu einer Funktion eines bestimmten Typs erstelle, würde ich auch das Fn deklarieren. z.B. NotificationFn<uint32_t> fn;
habe ich, was ich habe oben und ich diesen Fehler:
/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)
wo NotificationFnOld
die gleiche wie NotificationFn
ist
Was will ich tun in der Lage, die Funktion Signatur in einem sich ändern place (dh add/rem params) und an den typedef gebunden haben. Es macht mir nichts aus, neue typedefs in jeder Unterklasse zu deklarieren, solange ich nur einen Platz habe, um die Signatur zu ändern (natürlich muss ich die Funktionsimplementierungen ändern, aber ich möchte vermeiden, Zwischenvariablen und Zeug ändern zu müssen).
EDIT
Ich veränderte die typedef zu einem using
und bekam noch einen ähnlichen Fehler. Das ist, was ich früher ... Statt typedef std::function<void(T&)> NotificationFn;
I using NotificationFnOld = std::function<void(T&)>;
verwendet
Und das ist der Fehler, den ich bekam.
/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)
Der Fehler wird auf der Unterklasse berichtet ASingleNotifier
im Prototyp der überschriebenen Funktion RegisterNotification
. Es wird nicht beanstandet, wenn der Alias in dem in ANotifier
deklarierten Prototyp verwendet wird. Wie verwende ich den Alias in meinen Unterklassen sauber?
HINWEIS: NotificationFnOld
und NotificationFn
werden in dieser Frage austauschbar verwendet, ich verwende tatsächlich nur NotificationFnOld
in meinem Code.
EDIT
Incase Details benötigt werden, hier ist der Code von dem, was ich versuche. Es sollte keine Beziehung mit sein, aber wenn mehr Informationen benötigt werden, werde ich zur Verfügung stellen.
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;
};
Danke für die Hilfe/Anregungen
Kartik
Ich sehe kein Lambda in bereitgestellten Code. – SergeyA
Erhalten Sie Fehler, wenn Sie den typedef Weg versuchen? – aschepler
Die C++ 11 'using'-Syntax wird deutlicher als der alte 'typedef'-Mechanismus gelesen, sollte stattdessen verwendet werden. – kfsone