шаблоны — передача аргументов диспетчера C ++

У меня есть простая структура диспетчера, которая не будет компилироваться и, честно говоря, я понятия не имею, почему.

Поэтому я создал диспетчер, с помощью которого вы можете связать функцию с именем update, она будет вызывать статическую функцию-член invoke, которая разыменовывает экземпляр объекта и вызывает метод с простым std::ostream ссылка

По некоторым причинам это не компилируется, но мне кажется, что это правильно.
Компилятор не даст хорошего результата: /

заранее спасибо

#include <iostream>
#include <list>
#include <utility>

namespace trd {

struct dispatcher {
public:
template<typename C, void(C::*M)(std::ostream & os) = C::update>
static void invoke(void * instance, std::ostream & os) {
(static_cast<C*>(instance)->*M)(os);
}

template<typename C, void(C::*M)(std::ostream & os) = &C::update>
void bind(C * instance) {
instances.push_back(std::make_pair(&invoke<C, M>, instance));
}

void operator () (std::ostream & os) {
for (auto & instance : instances)
(instance.first)(instance.second, os);
}

private:
std::list<std::pair<void(*)(std::ostream & os), void *>> instances;
};

}

struct test {
public:
void update(std::ostream & os) { os << "foo"; }
};

int main() {
trd::dispatcher dp;

test t;

dp.bind(&t);

dp(std::cout);

return 0;
}

2

Решение

Вы используете методы, а не функции, поэтому использование экземпляра как void является плохой практикой, используя приведение в стиле C.

Вместо этого C ++ имеет std::function и лямбды:

namespace trd {

struct dispatcher {
public:
template<typename C, void(C::*M)(std::ostream & os) = &C::update>
void bind(C * instance) {
instances.push_back([=](std::ostream & os){std::invoke(M, instance, os);});
}

void operator () (std::ostream & os) {
for (auto & instance : instances)
std::invoke(instance, os);
}

private:
std::list<std::function<void(std::ostream & os)>> instances;
};
}

Использование C ++ 17 для std::invoke,

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]