M
M
Makaleks2014-07-03 00:30:50
C++ / C#
Makaleks, 2014-07-03 00:30:50

How to pass as an argument a pointer to an array element - a class member?

I made my version of qsort, which would sort objects by some of their members:

template <class TIPE, typename T_M> void my_qsort(TIPE *buf, int first, int last, T_M TIPE::*m)
,
but here's the problem -
my_qsort(c,0,451,&color::number);//где number - int
works great and
my_qsort(c,0,451,&color::hsv[0]);//да-да - я хочу отсортировать массив объектов по первому элементу другого массива - члена этого класса
does not work at all (does not even compile)
I tried other options, but I could not do it
why
HSV - цветовая модель
И я хотел провести сортировку по H (тон цвета)
В классе хранится также и другой массив - RGB
color
struct color{
    int number;
    unsigned char rgb[3];
    double hsv[3];
    color(){};
  };

Need help
Thank you

Answer the question

In order to leave comments, you need to log in

4 answer(s)
M
malerix, 2014-07-03
@Makaleks

Use lambdas.

Or try this
#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:
Another couple of dirty hacks. never write like that
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;
}

And an example with lambdas
#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

Y
yttrium, 2014-07-03
@yttrium

what does the compiler throw out?

M
Misha Krinkin, 2014-07-03
@kmu1990

You can pass a pointer to the array itself, but, as far as I know, this syntax will not allow you to pass an index in this array - it must be passed separately, i.e. something like this:

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]) {
        ...
    }
    ...
}

Yes, and it would be strange to allow it, the class member is the entire array, and not a separate element of this array.
But it's better, of course, to write a functor, or use lambdas.

X
xandox, 2014-07-03
@xandox

Why didn't funcotors please you?

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question