сравнение member fucntion pointers
От: niXman Ниоткуда https://github.com/niXman
Дата: 31.03.20 09:50
Оценка:
привет!

вопрос скорее не про сравнение, но про поиск среди множества MFP одного конкретного.

ситуация: есть некоторое кол-во MFP. сейчас сабж реализован таким способом:
struct type {
    struct mf_stat {
        ...
    };

    template<typename ...Args>
    const mf_stat* get_stat(void(type::*mf)(Args...)) const {
        if ( mem_fn_ptr_equal(&type::m0, mf) ) {
            return std::addressof(m0_stat);
        }
        if ( mem_fn_ptr_equal(&type::m1, mf) ) {
            return std::addressof(m1_stat);
        }
        if ( mem_fn_ptr_equal(&type::m2, mf) ) {
            return std::addressof(m2_stat);
        }

        return nullptr;
    }

private:
    template<typename P>
    static bool mem_fn_ptr_equal(P l, P r) { return l == r; }
    template<typename PL, typename PR>
    static bool mem_fn_ptr_equal(PL, PR) { return false; }

private:
    void m0(int) {}
    mf_stat m0_stat;

    void m1(char) {}
    mf_stat m1_stat;

    void m2(float) {}
    mf_stat m2_stat;
};


обратите внимание на функцию get_stat(). эта финукция генерится препроцессором, т.е. не руками. но вопрос не в этом. вопрос в красивости =)
можно ли как-то это сделать по-красивей и переносимей?
в масив-то не положишь их — сигнатуры могут быть разными...
в switch() — тоже, но не из-за сигнатур.

какие идеи?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: сравнение member fucntion pointers
От: rg45 СССР  
Дата: 31.03.20 10:24
Оценка:
Здравствуйте, niXman, Вы писали:

X>вопрос скорее не про сравнение, но про поиск среди множества MFP одного конкретного.

X>ситуация: есть некоторое кол-во MFP. сейчас сабж реализован таким способом:
X>обратите внимание на функцию get_stat(). эта финукция генерится препроцессором, т.е. не руками. но вопрос не в этом. вопрос в красивости =)
X>можно ли как-то это сделать по-красивей и переносимей?
X>в масив-то не положишь их — сигнатуры могут быть разными...
X>в switch() — тоже, но не из-за сигнатур.

X>какие идеи?


Сделать get_stat метафункцией — такой вариант не катит? Ну то есть, сделать входной указатель на функцию-член параметром шаблона и результат вычислить в компайл-тайме путем набора специализаций?
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 31.03.2020 10:25 rg45 . Предыдущая версия .
Re: сравнение member fucntion pointers
От: sergii.p  
Дата: 31.03.20 10:25
Оценка:
Здравствуйте, niXman, Вы писали:

X>какие идеи?


так почему указатели не преобразовать например к long long и затем уже запихнуть в массив?
Re[2]: сравнение member fucntion pointers
От: rg45 СССР  
Дата: 31.03.20 10:27
Оценка: +2
Здравствуйте, sergii.p, Вы писали:

SP>так почему указатели не преобразовать например к long long и затем уже запихнуть в массив?


Потому что это не указатели, а указатели-на-члены и запросто могут не уместиться в long long. Ну и типовая безопасноть идет лесом при таком подходе.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 31.03.2020 10:31 rg45 . Предыдущая версия .
Re[2]: сравнение member fucntion pointers
От: niXman Ниоткуда https://github.com/niXman
Дата: 31.03.20 10:47
Оценка:
Здравствуйте, rg45, Вы писали:

R>Сделать get_stat метафункцией — такой вариант не катит? Ну то есть, сделать входной указатель на функцию-член параметром шаблона и результат вычислить в компайл-тайме путем набора специализаций?


если я тебя правильно понял — тогда идентификатором мембер-функции будет сигнатура?
а значит, два мембера-функции с одинаковой сигнатурой будут восприниматься как одно и тоже?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 31.03.2020 10:48 niXman . Предыдущая версия .
Re[3]: сравнение member fucntion pointers
От: rg45 СССР  
Дата: 31.03.20 12:08
Оценка: 9 (1) +1
Здравствуйте, niXman, Вы писали:

R>>Сделать get_stat метафункцией — такой вариант не катит? Ну то есть, сделать входной указатель на функцию-член параметром шаблона и результат вычислить в компайл-тайме путем набора специализаций?


X>если я тебя правильно понял — тогда идентификатором мембер-функции будет сигнатура?

X>а значит, два мембера-функции с одинаковой сигнатурой будут восприниматься как одно и тоже?

Нет-нет, параметром должен стать именно указатель на фунцию-член — нетиповой параметр шаблона. Правда там и тип тоже придется таскать за собой, к сожалению, поэтому везде появляется эдакое заикание, вида: get_stat<decltype(&type::m1), &type::m1>(). Но этот тот случай, когда можно и макросом не побрезговать.

http://coliru.stacked-crooked.com/a/2ca568933ca04de8

#include <iostream>

struct type {
    struct mf_stat {
    };

    template <typename T, T>
    const mf_stat* get_stat() const;

    void m0(int) {}
    mf_stat m0_stat;
    
    void m1(char) {}
    mf_stat m1_stat;

    void m2(float) {}
    mf_stat m2_stat;

};

template <typename T, T>
const type::mf_stat* type::get_stat() const { return nullptr; }

template <>
const type::mf_stat* type::get_stat<decltype(&type::m0), &type::m0>() const { return &m0_stat; }

template <>
const type::mf_stat* type::get_stat<decltype(&type::m1), &type::m1>() const { return &m1_stat; }

template <>
const type::mf_stat* type::get_stat<decltype(&type::m2), &type::m2>() const { return &m2_stat; }


int main() {

    const type t;

    std::cout << std::boolalpha;
    std::cout << t.get_stat<decltype(&type::m0), &type::m0>() << std::endl;
    std::cout << t.get_stat<decltype(&type::m1), &type::m1>() << std::endl;
    std::cout << t.get_stat<decltype(&type::m2), &type::m2>() << std::endl;
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 31.03.2020 12:17 rg45 . Предыдущая версия . Еще …
Отредактировано 31.03.2020 12:16 rg45 . Предыдущая версия .
Re: сравнение member fucntion pointers
От: _NN_ www.nemerleweb.com
Дата: 31.03.20 12:20
Оценка:
Здравствуйте, niXman, Вы писали:

X>привет!


X>вопрос скорее не про сравнение, но про поиск среди множества MFP одного конкретного.


get_stat генерируется, а сами методы и mf_stat тоже или вручную ?

X>в масив-то не положишь их — сигнатуры могут быть разными...


Как насчёт перегрузки get_stat по типам и хранением списков методов по типам ?

Тогда как минимум не нужно будет перебирать лишние функции

[[nodiscard]] constexpr const mf_stat* get_stat(void(type::*mf)()) const noexcept
{
  return void_void_functions.try_get(mf);
}

[[nodiscard]] constexpr const mf_stat* get_stat(void(type::*mf)(int)) const noexcept
{
  return void_int_functions.try_get(mf);  
}

[[nodiscard]] constexpr const mf_stat* get_stat(void(type::*mf)(float)) const noexcept
{
  return void_float_functions.try_get(mf);  
}


static constexpr MFPMap void_void_functions{ {&type::mfa, &ma_stat}, {&type::mfb, &mb_stat} };
static constexpr MFPMap void_int_functions{ {&type::mfc, &mc_stat} };
static constexpr MFPMap void_float_functions{ {&type::mfd, &md_stat}, {&type::mfe, &me_stat}, {&type::mfh, &mh_stat}  };

class compile_time_map<Key, Value>
{
   [[nodiscard]] constexpr Value* try_get(Key const& key) noexcept { сравнение и возврат пары }
};


Ну или как-нибудь через std::array<std::tuple<MFP, mf_stat>>
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: сравнение member fucntion pointers
От: rg45 СССР  
Дата: 31.03.20 12:25
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Как насчёт перегрузки get_stat по типам и хранением списков методов по типам ?


Как я понял, у него возможно существование двух и более функций-членов одного типа.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: сравнение member fucntion pointers
От: _NN_ www.nemerleweb.com
Дата: 31.03.20 12:29
Оценка: 10 (1) +1
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, _NN_, Вы писали:


_NN>>Как насчёт перегрузки get_stat по типам и хранением списков методов по типам ?


R>Как я понял, у него возможно существование двух и более функций-членов одного типа.


Так я и предлагаю для каждого типа создавать свой список.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: сравнение member fucntion pointers
От: rg45 СССР  
Дата: 31.03.20 13:50
Оценка: 9 (1) +1
Здравствуйте, _NN_, Вы писали:

_NN>Так я и предлагаю для каждого типа создавать свой список.


Как-то так

http://coliru.stacked-crooked.com/a/b22520a09d50e23d

#include <iostream>
#include <map>

template <typename T>
const std::array<std::byte, sizeof(T)>& get_dump(const T& t) {
    return reinterpret_cast<const std::array<std::byte, sizeof(T)>&>(t);
}

struct dump_less {
    template <typename T>
    bool operator()(const T& lhs, const T& rhs) const { 
        return get_dump(lhs) < get_dump(rhs);
    }
};

struct type {
    struct mf_stat {
    };

    template<typename...Args>
    const mf_stat* get_stat(void(type::*mf)(Args...)) const {
        using T = decltype(mf);
        const auto it = m_stat_map<T>.find(mf);
        return it != m_stat_map<T>.end() ? &(this->*(it->second)) : nullptr;
    }

    void m0(int) {}
    mf_stat m0_stat;
    
    void m1(int) {}
    mf_stat m1_stat;
    
    void m2(char) {}
    mf_stat m2_stat;
    
    void m3(char) {}
    mf_stat m3_stat;
    
    void m4(float) {}
    mf_stat m4_stat;
    
    void m5(float) {}
    mf_stat m5_stat;

private:

    template <typename T>
    using stat_map = std::map<T, mf_stat type::*, dump_less>;

    template <typename T>
    static const stat_map<T> m_stat_map;
};

template <>
const type::stat_map<void (type::*)(int)> type::m_stat_map<void (type::*)(int)> {
    {&type::m0, &type::m0_stat},
    {&type::m1, &type::m1_stat}
};

template <>
const type::stat_map<void (type::*)(char)> type::m_stat_map<void (type::*)(char)> {
    {&type::m2, &type::m2_stat},
    {&type::m3, &type::m3_stat}
};

template <>
const type::stat_map<void (type::*)(float)> type::m_stat_map<void (type::*)(float)> {
    {&type::m4, &type::m4_stat},
    {&type::m5, &type::m5_stat}
};


int main() {

    const type t;
    std::cout << t.get_stat(&type::m0) << std::endl;
    std::cout << t.get_stat(&type::m1) << std::endl;
    std::cout << t.get_stat(&type::m2) << std::endl;
    std::cout << t.get_stat(&type::m3) << std::endl;
    std::cout << t.get_stat(&type::m4) << std::endl;
    std::cout << t.get_stat(&type::m5) << std::endl;
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: сравнение member fucntion pointers
От: kov_serg Россия  
Дата: 31.03.20 13:54
Оценка: 9 (1) +1
Здравствуйте, niXman, Вы писали:

X>привет!

...
X>обратите внимание на функцию get_stat(). эта финукция генерится препроцессором, т.е. не руками. но вопрос не в этом. вопрос в красивости =)
X>можно ли как-то это сделать по-красивей и переносимей?
X>в масив-то не положишь их — сигнатуры могут быть разными...
X>в switch() — тоже, но не из-за сигнатур.

X>какие идеи?

Я конечно понимаю что цель это просто сбор статистики по функциям. Но так как в C++ соверешшно у@$&щные указатели на члены класса
Я бы использовал другие идентификаторы, напимер enum с названиями функций.
#include <stdio.h>
struct Info {
    double x;
    Info() { x=0; }
};
struct Scope{ Scope(Info& info) { info.x=info.x+1; } };

struct A {
    struct Member { 
        enum ID { UB, fn_void,fn1,fn2,fn_int, MAX }; 
        template<class T> static int id(T t) {
            if (cmp(t,static_cast<void(A::*)()>(&A::fn))) return fn_void;
            if (cmp(t,&A::fn1)) return fn1;
            if (cmp(t,&A::fn2)) return fn2;
            if (cmp(t,static_cast<void(A::*)(int)>(&A::fn))) return fn_int;
            return UB;
        }
        static int id(enum ID id) { return id; }
        static int id(int id) { return id>UB && id<MAX ? id : UB; }
        template<class T> Info& operator[] (T t) { return info[id(t)]; }
    private:
        Info info[MAX];
        template<class T> static bool cmp(T a,T b) { return a==b; }
        template<class A,class B> static bool cmp(A a,B b) { return false; }
    } member;
    void fn() { Scope scope(member[Member::fn_void]); 
    }
    void fn1() { Scope scope(member[Member::fn1]);
    }
    void fn2() { Scope scope(member[Member::fn2]);
    }
    void fn(int) { Scope scope(member[Member::fn_int]); 
    }
};

int main(int argc, char const *argv[]) {
    A a;
    a.member[&A::fn1].x=3.14;
    a.member[A::Member::fn_void].x=1.41;
    a.member[A::Member::fn_int].x=2.71;

    printf("id=%d x=%g\n",A::Member::fn1     , a.member[A::Member::fn1].x );
    printf("id=%d x=%g\n",A::Member::fn2     , a.member[A::Member::fn2].x );
    printf("id=%d x=%g\n",A::Member::fn_int  , a.member[A::Member::fn_int].x );    
    printf("id=%d x=%g\n",A::Member::fn_void , a.member[A::Member::fn_void].x );

    printf("id=%d x=%g\n",A::Member::id(&A::fn1)                              , a.member[&A::fn1].x        );
    printf("id=%d x=%g\n",A::Member::id(&A::fn2)                              , a.member[&A::fn2].x        );
    printf("id=%d x=%g\n",A::Member::id(static_cast<void(A::*)(int)>(&A::fn)) , a.member[static_cast<void(A::*)(int)>(&A::fn)].x );
    printf("id=%d x=%g\n",A::Member::id(static_cast<void(A::*)()>(&A::fn))    , a.member[static_cast<void(A::*)()>(&A::fn)].x );

    return 0;
}
Отредактировано 31.03.2020 14:01 kov_serg . Предыдущая версия . Еще …
Отредактировано 31.03.2020 14:00 kov_serg . Предыдущая версия .
Re[5]: сравнение member fucntion pointers
От: niXman Ниоткуда https://github.com/niXman
Дата: 31.03.20 14:00
Оценка:
Здравствуйте, rg45, Вы писали:

R>Как-то так


спасибо большое, но как-то совсем сложно получилось =)
да еще и с дополнительными аллокациями...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: сравнение member fucntion pointers
От: niXman Ниоткуда https://github.com/niXman
Дата: 31.03.20 14:02
Оценка: :)
Здравствуйте, kov_serg, Вы писали:

_>Я конечно понимаю что цель это просто сбор статистики по функциям. Но так как в C++ соверешшно у@$&щные указатели на члены класса

_>Я бы использовал другие идентификаторы, напимер enum с названиями функций.

коллеги, а может ну её, эту красоту, и так все и оставить?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: сравнение member fucntion pointers
От: kov_serg Россия  
Дата: 31.03.20 14:07
Оценка:
Здравствуйте, niXman, Вы писали:

X>коллеги, а может ну её, эту красоту, и так все и оставить?

В любой непонятной ситуации:
Re[3]: сравнение member fucntion pointers
От: rg45 СССР  
Дата: 31.03.20 14:16
Оценка: :)
Здравствуйте, niXman, Вы писали:

X>коллеги, а может ну её, эту красоту, и так все и оставить?


Мы осознанно подталкиваем тебя к этому выводу
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 31.03.2020 14:21 rg45 . Предыдущая версия .
Re[6]: сравнение member fucntion pointers
От: _NN_ www.nemerleweb.com
Дата: 31.03.20 14:36
Оценка:
Здравствуйте, niXman, Вы писали:

X>Здравствуйте, rg45, Вы писали:


R>>Как-то так


X>спасибо большое, но как-то совсем сложно получилось =)

X>да еще и с дополнительными аллокациями...

Не нужно пользоваться std::map.
Достаточно массива или своего compile_time_map и оформить всё в constexpr

https://github.com/mapbox/eternal
https://stackoverflow.com/questions/16490835/how-to-build-a-compile-time-key-value-store
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: сравнение member fucntion pointers
От: rg45 СССР  
Дата: 31.03.20 14:43
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Не нужно пользоваться std::map.

_NN>Достаточно массива или своего compile_time_map и оформить всё в constexpr

Использование compile_time_map подразумевает, что указатель на функцию-член должен быть константой времени компиляции? Это означает, что мы должны передать его не через список параметров функции, а как нетиповой параметр шаблона, наподобие как здесь
Автор: rg45
Дата: 31.03.20
. Так ведь? Но если мы можем себе это позволить, то решение становится простым и без всяких compile_time_map.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 31.03.2020 14:50 rg45 . Предыдущая версия . Еще …
Отредактировано 31.03.2020 14:45 rg45 . Предыдущая версия .
Re[8]: сравнение member fucntion pointers
От: _NN_ www.nemerleweb.com
Дата: 31.03.20 15:09
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, _NN_, Вы писали:


_NN>>Не нужно пользоваться std::map.

_NN>>Достаточно массива или своего compile_time_map и оформить всё в constexpr

R>Использование compile_time_map подразумевает, что указатель на функцию-член должен быть константой времени компиляции? Это означает, что мы должны передать его не через список параметров функции, а как нетиповой параметр шаблона, наподобие как здесь
Автор: rg45
Дата: 31.03.20
. Так ведь? Но если мы можем себе это позволить, то решение становится простым и без всяких compile_time_map.


Не обязательно.
Это даст нам возможность создать словарь без динамической аллокации.

Грубо говоря заменить

 template <typename T>
    using stat_map = std::map<T, mf_stat type::*, dump_less>;



На

{
   ...

   template <typename T>
    using stat_map = std::array<std::pair<T, mf_stat type::*, dump_less>>;

   template <typename T>
   static constexpr stat_map<T> m_stat_map;
 
  template <>
  static constexpr stat_map<void (type::*)(int)> m_stat_map<void (type::*)(int)> {
    {&type::m0, &type::m0_stat},
    {&type::m1, &type::m1_stat}
  };

}


Я не уверен если можно переменные специализировать так тоже. Если нельзя то обернуть в тип.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: сравнение member fucntion pointers
От: reversecode google
Дата: 31.03.20 15:14
Оценка:
а зачем нужны вот эти все

    void m0(int) {}
    mf_stat m0_stat;

    void m1(char) {}
    mf_stat m1_stat;


я всегда пересматриваю задачу изначально
а не какие то сравнения
может
что то в таком духе надо переделать ?
    void m0(int) {}
    mf_stat m0_stat(m0);

    void m1(char) {}
    mf_stat m1_stat(m1);
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.