Параметр шаблона C ++ в качестве указателя на член будет эффективным способом вызова по ссылке? - PullRequest
2 голосов
/ 10 июня 2019
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(). Верно?

В заключение

  1. Я использую тот факт, что указатель на член равен constexpr и поэтому может быть аргументом шаблона.
  2. Таким образом, я могу создать шаблон функции, который имитирует fun_static1().
  3. Теперь мне не нужно передавать фактический адрес каждого члена. Скорее, созданные функции будут иметь твердое смещение и могут напрямую его использовать.
  4. Он не тратит ресурсы времени выполнения и не играет опасно с void* для вычисления смещения элемента.

Я прав? Тогда я должен на самом деле реализовать fun_static2() всякий раз, когда я серьезно беспокоюсь о производительности во время выполнения? (Я никогда не буду этого делать, только из любопытства)

Редактировать - Если вам не нужен шаблон, просто подумайте, что я хочу повторно использовать fun_dynmaic_() над Apple членами, Banana и так далее. Тогда реализация fun_static2(), а не fun_dynamic() будет утомительным, но (кажется, более быстрым) решением, если имеется много переменных.

Edit2 - Три функции выполняют одно и то же: копируют значение a, b, c и помещают в кортеж. (и это только пример)

...