问题描述:

Consider a class card which has two public members, int suit and int value, and a template function that sorts an array of cards by the member I pass through a pointer-to-member, like this:

//class card with public members

class card{

public:

int suit;

int value;

};

//sorting algorithm

template<typename m_pointer, typename iterator, typename Functype>

void sort_array(m_pointer member, iterator begin, iterator end, Functype pred){

iterator iter1=begin;

while(iter1!=end && ++iter1!=end){

iterator iter2=iter1;

while(iter2!=begin){

iterator iter3=iter2;

--iter3;

//here i use the pointer-to-member to sort the cards

if(pred((*iter3).*member, (*iter2).*member)){

std::swap(*iter3, *iter2);

}

else break;

--iter2;

}

}

}

int main(){

card array[3]={{3,1},{2,3},{4,5}};

//let's sort the cards by the suit value in a decreasing order

sort(&card::suit, array, array+3, [](int a, int b){return a<b;});

}

If the card member suit is public there's obviously no problem, but what actually i didn't expected is that the same code doesn't give any trouble even if i declare suit or value as private members.

class card{

int suit;

int value;

public://adding this for clarity, read forward

int* pointer_to_suit();

};

From what I know, I shouldn't be able to access private members from outside the class, and the only way to pass a pointer-to-member to a private member is through a member function which returns the member address, like this for example:

//function member of the class card

int* card::pointer_to_suit(){

return &suit;

}

So, why is it possible that the code above (the one with the template) works?

EDIT:

Ok, the code above doesn't compile on it's own, but for some reason the following code compile fine to me. I'll post the whole code since I've no idea where the trick for it to work might be, sorry for the mess:

template<typename m_pointer, typename iterator, typename Functype>

void sort_array(m_pointer member, iterator begin, iterator end, Functype pred){

iterator iter1=begin;

while(iter1!=end && ++iter1!=end){

iterator iter2=iter1;

while(iter2!=begin){

iterator iter3=iter2;

--iter3;

if(pred((*iter3).*puntatore, (*iter2).*puntatore)){

std::swap(*iter3, *iter2);

}

else break;

--iter2;

}

}

}

class card{

int suit;

int value;

public:

card(): suit(0), value(0) {}

card(int a, int b): suit(a), value(b){}

bool operator==(card a){return (suit==a.get_s() && value==a.get_v());}

bool operator!= (card a){return !(*this==a);}

void set_values(int a, int b){suit=a; value=b;}

int get_v(){return value;}

void set_v(int v){value=v;}

int get_s(){return suit;}

void set_s(int s){suit=s;}

double points_card();

};

template<typename iterator>

void ordina(iterator begin, iterator end, short (&suit)[4]){

for(int i=0; i<4; i++) suit[i]=0;

iterator it1=begin;

while(it1!=end){

if((*it1).get_s()==1) suit[0]+=1;

else if((*it1).get_s()==2) suit[1]+=1;

else if((*it1).get_s()==3) suit[2]+=1;

else if((*it1).get_s()==4) suit[3]+=1;

++it1;

}

sort_array(&carte::suit, begin, end, [](char a, char b){

if(b==0) return false;

else if(a==0) return true;

return (a>b);

});

sort_array(&carte::value, begin, begin+suit[0], [](int a, int b){return (a<b);});

sort_array(&carte::value, begin+suit[0], begin+suit[0]+suit[1], [](int a, int b){return (a<b);});

sort_array(&carte::value, begin+suit[0]+suit[1], begin+suit[0]+suit[1]+suit[2], [](int a, int b){return (a<b);});

sort_array(&carte::value, begin+suit[0]+suit[1]+suit[2], begin+suit[0]+suit[1]+suit[2]+suit[3],[](int a, int b){return (a<b);});

}

int main(){

card array[5]={{2,3},{1,2},{3,4},{4,5},{3,2}};

short suits[4]={1,1,2,1};

ordina(array, array+5, suits);

return 0;

}

EDIT 2: Yes, it runs http://coliru.stacked-crooked.com/a/d1795f0845770fcb . Please note that the code here is not translated and there are some lines i didn't add for brevity.

EDIT 3: As mentioned in Barry answer http://stackoverflow.com/a/35978073/5922196, this is a gcc compiler bug. I used g++ 4.9.2 and this bug is still unresolved

网友答案:

Congratulations, you found a bug in gcc! Here is a minimally reproduced example. Note that when we say minimal, we really do mean minimal. I found this by just repeatedly deleting most of your lines of code. Also, always include things which compiler you used. Would've helped.

gcc compiles this:

class X {
    int mem;
};

template <class T>
auto foo(T) {
    return &X::mem;
}

int main() {
    auto p = foo(0);
}

clang does not. clang is right. This is gcc bug 41437.

相关阅读:
Top