Здравствуйте, niXman, Вы писали:
[...]
X>для фундаментальных типов все просто — преобразуем args в массив указателей на void, и добавляем какие-то ID`ы, идентифицирующие типы.
X>но со всеми остальными(в том числе и юзерскими типами) типами все как-то не перспективно...
tuple здесь не поможет, т.к. для разных Args будут разные типы tuple. RTTI в виде std::type_index тоже как-то не очень. Идея с массивом void* правильная, но вместо идентифкаторв типов можно передавать массив функций-обработчиков для значения каждого типа:
#include <iostream>
struct shared_buffer {};
// то что тебе нужно делать для каждого типа
shared_buffer do_pack(int arg);
shared_buffer do_pack(double arg);
struct foo {
// пользовательскиме типы тоже не проблема
friend shared_buffer do_pack(foo const& arg);
};
struct somestruct {
template<typename... Args>
shared_buffer pack(const Args&... args) {
// заворачиваем do_pack для каждого типа в массив функций
arg_pack_fn fns[] = { &wrap_do_pack<Args>... };
// преобразуем аргументы в массив void const*
void const* data[] = { std::addressof(args)... };
return pack2(fns, data, sizeof...(Args));
}
private:
using arg_pack_fn = shared_buffer (*)(void const* arg);
// обертка для функций do_pack(T) чтобы привести к arg_pack_fn
template<typename T>
static shared_buffer wrap_do_pack(void const* arg) {
return do_pack(*static_cast<T const*>(arg));
}
shared_buffer pack2(arg_pack_fn pack_fns[], void const* args[], size_t count);
};
// implementation in .cpp
shared_buffer do_pack(int arg) {
std::cout << arg << ' ';
}
shared_buffer do_pack(double arg) {
std::cout << arg << ' ';
}
shared_buffer do_pack(foo const& arg) {
std::cout << "foo ";
}
shared_buffer somestruct::pack2(arg_pack_fn pack_fns[], void const* args[], size_t count) {
for (size_t i = 0; i != count; ++i) {
pack_fns[i](args[i]);
}
}
int main() {
somestruct ss;
ss.pack(foo{}, 1, 3.14); // should print "foo 1 3.14 "
}
http://ideone.com/Ol1KUx