RequestS want to use ReportUrlThread's function(send) .ReportUrlThread is a template class.
It look like below the code is that "request->process(reportUrl->send);",
how can I achieve it?
The codes below can't be through compilation.
int main()
{
typedef Threadpool<RequestS> ThreadpoolDealFromBS2;
ThreadpoolDealFromBS2 threadpool;
ReportUrlReq* req = new ReportUrlReq();
threadpool.appendReportHiUrl(req);
}
class RequestS {
public:
RequestS()
{
}
virtual ~RequestS()
{
}
virtual void process(void (*send)(bool &exp))
{
log(Info, "RequestS...fun");
}
};
class ReportUrlReq:public RequestS {
public:
ReportUrlReq();
~ReportUrlReq();
virtual void process(void (*send)(bool &exp))
{
log(Info, "ReportUrlReq...fun");
}
};
template< typename T >
class ReportUrlThread {
public:
ReportUrlThread(uint32_t id)
{
}
virtual ~ReportUrlThread()
{
}
void send(bool &exp)
{
}
Threadpool< T >* threadpool;
};
template< typename T >
class Threadpool
{
public:
Threadpool( std::vector<ReportUrlThread<T>*>& reportUrl);
~Threadpool();
bool appendReportHiUrl( T* request );
private:
static void* reportWorker( void* arg );
void reportRun(ReportUrlThread<T> *reportUrl);
pthread_t* m_ReportUrlThreads;
};
template< typename T >
Threadpool< T >::Threadpool( std::vector<ReportUrlThread<T>*>& reportUrl)
{
m_ReportUrlThreads = new pthread_t[reportUrlThreadNum];
for (int i = 0; i < 10; ++i)
{
ReportUrlThread<T> * reportUrlThread = reportUrl[i];
reportUrlThread->threadpool = this;
if( pthread_create( m_ReportUrlThreads + i, NULL, reportWorker, reportUrlThread ) != 0 )
{
delete [] m_ReportUrlThreads;
throw std::exception();
}
if( pthread_detach( m_ReportUrlThreads[i] ) )
{
delete [] m_ReportUrlThreads;
throw std::exception();
}
}
}
template< typename T >
void* Threadpool< T >::reportWorker( void* arg )
{
ReportUrlThread<T>* reportUrl = (ReportUrlThread<T>*)arg;
Threadpool* pool = reportUrl->threadpool;
pool->reportRun(reportUrl);
return pool;
}
template< typename T >
void Threadpool< T >::reportRun(ReportUrlThread<T> *reportUrl)
{
while ( ! m_ReportStop )
{
m_ReportQueuestat.wait();
m_ReportQueuelocker.lock();
if ( m_ReportWorkqueue.empty() )
{
m_ReportQueuelocker.unlock();
continue;
}
T* request = m_ReportWorkqueue.front();
m_ReportWorkqueue.pop_front();
reportDealNum++;
m_ReportWorkqueueSize = m_ReportWorkqueue.size();
request->process(reportUrl->send);
}
}
The actual error is, that you're passing the memberfunction reportUrl->send to request->process expecting an ordinary function. But a member function needs an instance of its class! If send depends on members of ReportUrlThread, you might want to pass an instance of ReportUrlThread (or a derived class implementing send):
virtual void process(ReportUrlThread<RequestS> *RepUrlThReqS) {
bool exp;
RepUrlThReqS->send(exp);
// ...
}
If not, you might want to use a static function:
static void send(bool &exp) {
// ...
}
You might even want to use a lambda function (which is quite a bit hacky here):
class RequestS {
public:
virtual void process(void(*send)(bool &exp, void* instance), void *instance) {
bool exp;
send(exp, instance);
}
};
template< typename T >
class ReportUrlThread {
public:
void send(bool &exp) { }
};
int main() {
ReportUrlThread<RequestS> *reportUrl = new ReportUrlThread<RequestS>;
RequestS *request = new RequestS;
request->process(
[](bool &exp, void* reportUrlA) {
((ReportUrlThread<RequestS> *)reportUrlA)->send(exp);
}, reportUrl);
}
And many more possibilities...
It's up to you to decide, which is the best solution in your case.
Related
I've defined the following serializer stack:
namespace discordpp {
using Snowflake = uint64_t;
}
namespace nlohmann {
template <> struct adl_serializer<discordpp::Snowflake> {
static void to_json(json &j, const discordpp::Snowflake sf) {
j = std::to_string(sf);
}
static void from_json(const json &j, discordpp::Snowflake sf) {
std::istringstream(j.get<std::string>()) >> sf;
}
};
template <typename T> struct adl_serializer<std::shared_ptr<T>> {
static void from_json(json &j, std::shared_ptr<T> &ptr) {
if (j.is_null()) {
ptr == nullptr;
} else {
ptr = std::make_shared<T>(j.get<T>());
}
}
static void to_json(json &j, const std::shared_ptr<T> &ptr) {
if (ptr.get()) {
j = *ptr;
} else {
j = nullptr;
}
}
};
template <typename T> struct adl_serializer<std::shared_ptr<const T>> {
static void from_json(json &j, std::shared_ptr<const T> &ptr) {
if (j.is_null()) {
ptr == nullptr;
} else {
ptr = std::make_shared<const T>(j.get<T>());
}
}
static void to_json(json &j, const std::shared_ptr<const T> &ptr) {
if (ptr.get()) {
j = *ptr;
} else {
j = nullptr;
}
}
};
template <typename T> struct adl_serializer<std::optional<T>> {
static void to_json(json &j, const std::optional<T> &opt) {
if (opt.has_value()) {
j = nullptr;
} else {
j = *opt;
}
}
static void from_json(const json &j, std::optional<T> &opt) {
if (j.is_null()) {
opt = std::nullopt;
} else {
opt = j.get<T>();
}
}
};
}
And I'm poking around with things like so:
class MessageIn : protected util::ObjectIn {
public:
...
opt<sptr<const Snowflake>> guild_id;
...
}
void from_json(const json &j, MessageIn *m) {
...
j["guild_id"].get<Snowflake>();
j["guild_id"].get<const Snowflake>();
j["guild_id"].get<sptr<const Snowflake>>();
m->guild_id = j["guild_id"].get<opt<sptr<const Snowflake>>>();
...
}
My compiler is throwing an error on the j["guild_id"].get<sptr<const Snowflake>>(); line with error: no matching function for call to ‘nlohmann::basic_json<>::get<discordpp::sptr<const long unsigned int> >() const’. Have I missed something?
The std::shared_ptr<const T> synthesizer is not needed.
In the from_json methods of both std::shared_ptr sythesizers the json parameter wasn't static.
Here is simplified sample of problem, featuring CRTP:
#include <type_traits>
#include <iostream>
enum ActionTypes {
eInit = 2 << 0,
eUpdate = 2 << 1,
eMultUpdate = 2 << 2
};
template <class Data,
unsigned Actions = eInit|eUpdate|eMultUpdate>
class ActionData
{
template<ActionTypes As /*???*/>
struct action {
static void exec(Data*) { std::cout << "ActionData:: /*dummy*/ exec()\n"; };
static void exec(Data*,int) { std::cout << "ActionData::/*dummy*/ exec(int)\n"; };
};
template<>
struct action < /*???*/ >
{
static void exec(Data*) { /*...*/ };
};
template<>
struct action < /*???*/ >
{
static void exec(Data*, int) { /*...*/ };
};
Data* derived() { return static_cast<Data*>(this); }
protected:
void init() { action<eInit>::exec(derived()); }
void update() { action<eUpdate>::exec(derived()); }
void update(int key) { action<eMultUpdate>::exec(derived()); }
public:
enum Keys { DEFAULT_KEY = -1 };
void call(ActionTypes a, int key = DEFAULT_KEY)
{
switch (a) {
case eInit:
init(); break;
case eUpdate:
if (key == DEFAULT_KEY)
update();
else
case eMultUpdate:
update(key);
}
}
};
class Test : public ActionData<Test, eUpdate>
{
public:
void update() { std::cout << "Test :: update()\n"; }
};
int main()
{
Test actor;
ActionTypes a = eInit;
actor.call(a, 0); // useless here but must be possible.
actor.call(eUpdate, 0);
actor.call(eUpdate);
}
Essentially not all derived classes may implement all handlers, a enum is used to declare that and a dummy version of handler must be called. The problem is that it's not possible to select any implementation but default one using enum and enable_if alone, it requires a non-type parameter, which stupefied me.
PS. Another problem is target platform is limited to C++98\C++03 or tr1 C++11 (no variadic templates). The awkward interface is a legacy of dynamic (but not used as such) polymorphic architecture using function pointers in a big C (not C++!) project. Necessity of pointers or vtable made system unstable to programmer errors leading to vtable being overwritten.
I didn't realize that I should use a partial specialization for all cases including where there is no match:
#include <type_traits>
#include <iostream>
enum ActionTypes {
eInit = 2 << 0,
eUpdate = 2 << 1,
eMultUpdate = 2 << 2
};
template <class Data,
unsigned Actions = eInit|eUpdate|eMultUpdate>
class ActionData
{
// Never gets selected
template<ActionTypes A, typename Enable = void > struct action {};
template< ActionTypes A >
struct action<A, typename std::enable_if<(A & Actions) == 0>::type >
{
static void exec(Data*) { std::cout << "ActionData:: /*dummy*/ exec()\n"; };
static void exec(Data*,int) { std::cout << "ActionData::/*dummy*/ exec(int)\n"; };
};
template< ActionTypes A >
struct action < A, typename std::enable_if<(A & Actions) == eInit>::type >
{
static void exec(Data* o) { o->Data::init(); };
};
template< ActionTypes A >
struct action < A, typename std::enable_if<(A & Actions) == eUpdate>::type >
{
static void exec(Data* o) { o->Data::update(); };
};
template< ActionTypes A >
struct action < A, typename std::enable_if<(A & Actions) == eMultUpdate>::type >
{
static void exec(Data* o, int key) { o->Data::update(key); };
};
Data* derived() { return static_cast<Data*>(this); }
protected:
void init() { action<eInit>::exec(derived()); }
void update() { action<eUpdate>::exec(derived()); }
void update(int key) { action<eMultUpdate>::exec(derived(), key); }
public:
enum Keys { DEFAULT_KEY };
void call(ActionTypes a, int key = DEFAULT_KEY)
{
switch (a) {
case eInit:
init(); break;
case eUpdate:
if (key == DEFAULT_KEY) {
update();
break;
} else {
case eMultUpdate:
update(key);
break;
};
}
}
};
class Test : public ActionData<Test, eUpdate>
{
public:
void update() { std::cout << "Test :: update()\n"; }
};
int main()
{
Test actor;
ActionTypes a = eInit;
actor.call(a, 0);
actor.call(eUpdate);
actor.call(eMultUpdate, 0);
}
I have class MyClass that can be modified by calling setX.
I want to know if an object of MyClass has been changed by calling isChanged.
In the code below, I don’t like to add setDirty or m_dataChanged in every method that can change the state of an object.
class ChangesHolder
{
private:
bool m_isChanged;
// boost::signals2::signal<void()> m_dataChanged;
// long m_stamps;
public:
ChangesHolder()
: m_isChanged{false}
// , m_stamps{0}
{
// m_dataChanged.connect(std::bind(&ChangesHolder::setDirty, this));
}
bool isChanged() const
{
return m_isChanged;
// return (m_stamps == 0);
}
void resetChanges()
{
m_isChanged = false;
// m_stamps = 0;
}
protected:
void setDirty()
{
m_isChanged = true;
// ++m_stamps;
}
}
class MyClass : public ChangesHolder
{
private:
int m_x;
public:
void setX(int x)
{
if (m_x != x)
{
m_x = x;
setDirty();
// m_dataChanged();
}
}
}
I want to register such methods like this:
template<typename ... Funcs>
void startTrack(Funcs ... funcs)
{
auto connect = [&](auto func)
{
// connect func to setDirty
};
do_foreach(connect, funcs ...);
}
MyClass::MyClass()
{
startTrack(&MyClass::setX, &MyClass::setY);
}
How can this be done or maybe there are other ways to do it?
I would like to do something like this:
class Base{};
class Specialized1 : public Base
{
public:
int GetCount(){ return 1; }
};
class Specialized2 : public Base
{
public:
bool IsCorrect() { return true; }
};
class Example
{
public:
template< class ATTR_CLASS, class RETURNED_PARAMETER_CLASS >
int GetPerfectAttributeIndex( const RETURNED_PARAMETER_CLASS & perfect_parameter, ***RETURNED_PARAMETER_CLASS (*function_to_call)()*** )
{
for ( int i = 0; i < AttributeCount; ++i )
{
if ( perfect_parameter ==
static_cast< ATTR_CLASS >( MyAttributeTable[ i ] )->function_to_call() )
{
return i;
}
}
return -1;
}
Base** MyAttributeTable;
int AttributeCount;
};
And the call would be:
example.GetPerfectAttributeIndex< Specialized1, int >( 1, &Specialized1::GetCount );
So I know that this code is not working because of the part between ***
But how can I change it to make it work? Using some C++11 magic?
Thank you for any help!
The problem is that function_to_call is not a pointer to member function. You should also downcast from Base* more safe with dynamic_cast and checking against nullptr afterwards.
class Base
{
public:
virtual ~Base() = default;
};
class Specialized1 : public Base
{
public:
int GetCount() { return 1; }
};
class Specialized2 : public Base
{
public:
bool IsCorrect() { return true; }
};
class Example
{
public:
template <class ATTR_CLASS, class RETURNED_PARAMETER_CLASS>
int GetPerfectAttributeIndex(
RETURNED_PARAMETER_CLASS const& perfect_parameter,
RETURNED_PARAMETER_CLASS(ATTR_CLASS::*function_to_call)()) // added ATTR_CLASS::
{
for(int i = 0; i < AttributeCount; ++i)
{
auto ptr = dynamic_cast<ATTR_CLASS*>(MyAttributeTable[i]);
if(!ptr)
{
// handle the case of an invalid cast
}
if(perfect_parameter == (ptr->*function_to_call)()) // extra parentheses added and ->* operator used
return i;
}
return -1;
}
Base** MyAttributeTable;
int AttributeCount;
};
This is a simple delegate class that only works for methods of the format void ClassType::MethodType( InputType& ), but can easily be expanded to more generic functions, not shown simply because it would be too large.
class Delegate
{
public:
Delegate( void ) : Object( NULL ), Argument( NULL ) { }
virtual ~Delegate( void ) { }
template <class ClassType, class InputType, void (ClassType::*MethodType)( InputType )>
void Create( ClassType* SetObject, void* SetArgument = NULL )
{
Object = SetObject;
Argument = SetArgument;
StaticCall = &CallMethod<ClassType, InputType, MethodType>;
}
template <class InputType>
inline void operator()( InputType InputValue ) const
{
(*StaticCall)( Object, static_cast<void*>(InputValue) );
}
inline void operator()( void ) const
{
(*StaticCall)( Object, Argument );
}
protected:
typedef void (*FunctionCallType)( void*, void* );
void* Object;
void* Argument;
FunctionCallType StaticCall;
private:
template <class ClassType, class InputType, void (ClassType::*MethodType)( InputType )>
static inline void CallMethod( void* SetObject, void* PassArgument )
{
(static_cast<ClassType*>( SetObject )->*MethodType)( static_cast<InputType>(PassArgument) );
}
};
It's flexible and can be used to pool callback classes, but one problem I have with it is that so far it's on par with (or even slower when used in large vectors like I plan to) than a virtual call if it's used as a base class. I'm looking for any suggestions on how to increase performance since I'm out of ideas, even if it affects functionality.
The simplest performance measuring code I used (with -O3) was:
class VirtualBase
{
public:
virtual void TestCall( int* Data ) {}
};
class VirtualTest : public VirtualBase
{
public:
VirtualTest() : Value(0) {}
void TestCall( int* Data )
{
Value += *Data;
}
private:
int Value;
};
class DelTest : public Delegate
{
public:
DelTest() : Value(0)
{
Create<DelTest, int*, &DelTest::TestCall>( this );
}
void TestCall( int* Data )
{
Value += *Data;
}
private:
int Value;
};
int main( int argc, char **argv )
{
clock_t start;
int Value = 1;
VirtualBase* NewBase = new VirtualTest;
start = clock();
for( size_t Index = 0; Index < 1000000000; ++Index )
{
NewBase->TestCall( &Value );
}
delete NewBase;
std::cout << (( std::clock() - start ) / (double)CLOCKS_PER_SEC) << std::endl;
Delegate* NewDBase = new DelTest;
start = clock();
for( size_t Index = 0; Index < 1000000000; ++Index )
{
NewDBase->operator()( &Value );
}
delete NewDBase;
std::cout << (( std::clock() - start ) / (double)CLOCKS_PER_SEC) << std::endl;
return 0;
}
I should mention that I'd like the class to stay non-template, as it makes classes using callbacks to anything easy to iterate through in a single vector.
You might want to look at this Lightweight Generic C++ Callbacks article on CodeProject
Some of the code from the linked article, showing the use of a function template to do the forwarding:
template<typename R, typename P1, typename P2>
class Callback
{
public:
typedef R (*FuncType)(void*, P1, P2);
Callback() : func(0), obj(0) {}
Callback(FuncType f, void* o) : func(f), obj(o) {}
R operator()(P1 a1, P2 a2)
{
return (*func)(obj, a1, a2);
}
private:
FuncType func;
void* obj;
};
template<typename R, class T, typename P1, typename P2, R (T::*Func)(P1, P2)>
R Wrapper(void* o, P1 a1, P2 a2)
{
return (static_cast<T*>(o)->*Func)(a1, a2);
}
class Foo
{
public:
float Average(int n1, int n2)
{
return (n1 + n2) / 2.0f;
}
};
float Calculate(int n1, int n2, Callback<float, int, int> callback)
{
return callback(n1, n2);
}
int main()
{
Foo f;
Callback<float, int, int> cb
(&Wrapper<float, Foo, int, int, &Foo::Average>, &f);
float result = Calculate(50, 100, cb);
// result == 75.0f
return 0;
}
There is also a great write up on stackoverflow here which will give you better insight.