@makaleks

Как передать аргументом указатель на элемент массива — члена класса?

Делал я свой вариант qsort, который сортировал бы объекты по какому-то их члену:
template <class TIPE, typename T_M> void my_qsort(TIPE *buf, int first, int last, T_M TIPE::*m)
,
но вот незадача -
my_qsort(c,0,451,&color::number);//где number - int
работает прекрасно, а
my_qsort(c,0,451,&color::hsv[0]);//да-да - я хочу отсортировать массив объектов по первому элементу другого массива - члена этого класса
не работает совсем (даже не компилируется)
я и другие варианты пробовал, но не смог никак

зачем
HSV - цветовая модель
И я хотел провести сортировку по H (тон цвета)
В классе хранится также и другой массив - RGB
color
struct color{
		int number;
		unsigned char rgb[3];
		double hsv[3];
		color(){};
	};


Нужна помощь
Спасибо
  • Вопрос задан
  • 2885 просмотров
Решения вопроса 1
@malerix
Используйте лямбды.
Или попробуйте вот это
#include <iostream>

template <class TIPE, typename T_M> void my_qsort(
    TIPE *buf, 
    int first, 
    int last, 
    T_M TIPE::*m
){
    std::cout << (buf->*m) << std::endl;
}

struct Color {
    union {
        char hsv[3];
        struct {
            char hsv0;
            char hsv1;
            char hsv2;
        };
    };
};

int main() {
    Color color = { "hs" };
    
    my_qsort(
        &color,
        0,
        0,
        &Color::hsv0
    );

    my_qsort(
        &color,
        0,
        0,
        &Color::hsv1
    );

    return 0;
}


UPD:

Ещё пара грязных хаков. Никогда так не пишите
template<typename T>
T cast2T(int dummy, ...){
    va_list args;
    va_start(args, dummy);
    
    T result = va_arg(args, T);

    va_end(args);
    return result;
}

template<typename T>
void* cast2ptr(T mp) {
    union {
        T mp;
        void* p;
    } caster = {mp};
    return caster.p;
}

template<typename T>
T castFromPtr(void* p) {
    union {
        void* p;
        T mp;
    } caster = {p};
    return caster.mp;
}
int main() {
    Color color = { "hs" };
    
    char (Color::*hsvA)[3] = &Color::hsv;
    char (Color::*hsvB) = cast2T<char (Color::*)>(0, cast2T<char*>(0, hsvA) + 1);

    my_qsort(
        &color,
        0,
        0,
        hsvB
    );

    char (Color::*hsvC) = castFromPtr<char (Color::*)>( ((char*) cast2ptr(hsvA)) + 1);

    my_qsort(
        &color,
        0,
        0,
        hsvC
    );

    return 0;
}

И пример с лямбдами
#include <iostream>

template <class _Ty, typename _Getter> void my_qsort(_Ty *buf, int first, int last, _Getter g){
    for(; first != last; first++) {
        std::cout << "VALUE[" << first << "] = " << g(buf[first]) << std::endl;
    }
}

struct Color {
    double hsv[3];
};

int main() {

    Color color[3] = {
        { 0.0, 0.1, 0.0 },
        { 0.0, 0.2, 0.0 },
        { 0.0, 0.3, 0.0 },
    };
    

    my_qsort(
        color,
        0,
        3,
        [](const Color& c) { return c.hsv[1]; }
    );

    return 0;
}
// g++ main.cpp -std=c++0x -o main
// ./main
// VALUE[0] = 0.1
// VALUE[1] = 0.2
// VALUE[2] = 0.3

Ответ написан
Пригласить эксперта
Ответы на вопрос 3
yttrium
@yttrium
что компилятор выругивает?
Ответ написан
Можно передать указатель на сам массив, но, на сколько я знаю, передать индекс в этом массиве такой синтаксис не позволит - его нужно передавать отдельно, т. е. как-то так:

template <typename T, typename V>
void sort(T *array, int first, int last, int index, V (T::*member)) {
    ...
    if ((array[i].*member)[index] < (array[j].*member)[index]) {
        ...
    }
    ...
}


Да и странно это было бы позволять, мембером класса является именно массив целиком, а не отдельный элемент этого массива.

Но лучше, конечно, написать функтор, либо использовать лямбды.
Ответ написан
Комментировать
@xandox
А чем функоторы-то не угодили?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы