I aim to create a call queue to schedule work for another thread.
I'm using a virtual base class for type erasure and placement new for reducing the number of allocations, but, as far as I know, reinterpret_cast<Base*>(raw_ptr)
is UB.
Is there any other way to implement it?
class FuncWrapperInterface
{
public:
virtual ~FuncWrapperInterface() = default;
virtual void operator()() = 0;
virtual size_t size() = 0;
};
template<typename Func>
class FuncWrapper : public FuncWrapperInterface
{
public:
FuncWrapper(Func&& func)
: func_{std::move(func)}
{
}
void operator()() override
{
func_();
}
size_t size() override;
private:
Func func_;
};
template<typename Func>
size_t FuncWrapper<Func>::size()
{
return sizeof(*this);
}
class FuncQueue
{
public:
template<typename Func>
void add(Func&& func)
{
auto start{data_.size()};
data_.resize(data_.size() + sizeof(FuncWrapper<Func>));
new (data_.data() + start) FuncWrapper<Func>{std::move(func)};
}
void execute()
{
for (size_t idx{0}; idx < data_.size();)
{
// problem here
auto fw{std::launder(reinterpret_cast<FuncWrapperInterface*>(data_.data() + idx))};
(*fw)();
idx += fw->size();
fw->~FuncWrapperInterface();
}
data_.clear();
}
private:
std::vector<std::byte> data_;
};
UPD: I assume storing a pointer to FuncWrapperInterface
will solve that problem. Only alignment and exception/destruction issues remain.
Correct me if I am wrong.
minimal example:
int main()
{
FuncQueue fq;
fq.add([&]() { std::cout << "3" << std::endl; });
fq.add([&]() { std::cout << "2" << std::endl; });
fq.add([&]() { std::cout << "1" << std::endl; });
fq.add([&]() { std::cout << "Success" << std::endl; });
fq.execute();
}
void Command(int arg) { data.write(eCommandId); data.write(arg); }
Executor:void Exec() { Command c = readCommand(); switch(c)...
\$\endgroup\$