template<class T, typename... Args>
class Wrapper
{
// simple way of representing pointer-to-member
template <class T, class V>
using mv = V T::*;
public:
// non-type arguments (which are pointers to member)
template<mv<T, Args>... Ptrs>
static void fun(T* t)
{
make_tuple(t->*Ptrs...);
}
};
// inefficient one
template <typename... Args>
void fun_dynmaic_(Args&... args)
{
make_tuple(args...);
}
// actual class
class Apple
{
int a; float b; string c;
public:
Apple(int a, float b, const string& c) : a(a), b(b), c(c) {}
void fun_dynamic()
{
fun_dynmaic_(a, b, c);
}
void fun_static1()
{
make_tuple(a, b, c);
}
void fun_static2()
{
Wrapper<Apple, int, float, string>::fun<&Apple::a, &Apple::b, &Apple::c>(this);
}
};
У меня есть работа для всех переменных-членов некоторого класса.
Давайте предположим, что это просто make_tuple()
.
Здесь я привел 3 реализации этого.
Я не уверен, но после оптимизации компиляции и компиляции fun_static1()
и fun_static2()
будут скомпилированы в почти такой же эффективный машинный код. Это будет выглядеть так: возьмите указатель на Apple
и используйте сплошное смещение для прямого доступа к каждому элементу.
fun_dynamic()
работает хорошо, но переносит все адреса переменных. Так что это должно быть неэффективно.
В большинстве случаев лучше выбрать fun_static1()
. Это просто и быстро. Тем не менее, в некоторых случаях я мог бы быть в некотором огромном требовании. Например, существует class Banana, class Orange ...
, и задача (которая должна выполняться для всех членов Apple, Banana..
) может быть очень сложной, но многократно используемой процедурой (не только make_tuple()
). Если тогда мне нужен шаблон.
fun_static1()
не может использоваться в этом случае. Если мне нужна производительность во время выполнения, я должен выбрать fun_static2()
вместо fun_dynamic()
. Верно?
В заключение
- Я использую тот факт, что указатель на член равен
constexpr
и поэтому может быть аргументом шаблона.
- Таким образом, я могу создать шаблон функции, который имитирует
fun_static1()
.
- Теперь мне не нужно передавать фактический адрес каждого члена. Скорее, созданные функции будут иметь твердое смещение и могут напрямую его использовать.
- Он не тратит ресурсы времени выполнения и не играет опасно с
void*
для вычисления смещения элемента.
Я прав? Тогда я должен на самом деле реализовать fun_static2()
всякий раз, когда я серьезно беспокоюсь о производительности во время выполнения?
(Я никогда не буду этого делать, только из любопытства)
Редактировать - Если вам не нужен шаблон, просто подумайте, что я хочу повторно использовать fun_dynmaic_()
над Apple
членами, Banana
и так далее. Тогда реализация fun_static2()
, а не fun_dynamic()
будет утомительным, но (кажется, более быстрым) решением, если имеется много переменных.
Edit2 - Три функции выполняют одно и то же: копируют значение a, b, c и помещают в кортеж. (и это только пример)