tratando de compilar el siguiente código me sale este error de compilación, ¿qué puedo hacer?
ISO C ++ prohíbe tomar la dirección de una función miembro no estática no calificada o entre paréntesis para formar un puntero a la función miembro.
class MyClass {
int * arr;
// other member variables
MyClass() { arr = new int[someSize]; }
doCompare( const int & i1, const int & i2 ) { // use some member variables }
doSort() { std::sort(arr,arr+someSize, &doCompare); }
};

Andreas Brick
doCompare
debe ser static
. Si doCompare
necesita datos de MyClass
podrías convertir MyClass
en un funtor de comparación cambiando:
doCompare( const int & i1, const int & i2 ) { // use some member variables }
dentro
bool operator () ( const int & i1, const int & i2 ) { // use some member variables }
y llamando:
doSort() { std::sort(arr, arr+someSize, *this); }
Además, ¿no es doSort
falta un valor de retorno?
Creo que debería ser posible usar std::mem_fun
y algún tipo de enlace para convertir la función miembro en una función libre, pero la sintaxis exacta se me escapa en este momento.
EDITAR: doh, std::sort
toma la función por valor, lo que puede ser un problema. Para evitar esto, ajuste la función dentro de la clase:
class MyClass {
struct Less {
Less(const MyClass& c) : myClass(c) {}
bool operator () ( const int & i1, const int & i2 ) {// use 'myClass'}
MyClass& myClass;
};
doSort() { std::sort(arr, arr+someSize, Less(*this)); }
}

Klaim
Como dice Andreas Brinck, doCompare debe ser estático (+1). Si TIENE QUE tener un estado en su función de comparación (usando los otros miembros de la clase), entonces será mejor que use un funtor en lugar de una función (y eso será más rápido):
class MyClass{
// ...
struct doCompare
{
doCompare( const MyClass& info ) : m_info(info) { } // only if you really need the object state
const MyClass& m_info;
bool operator()( const int & i1, const int & i2 )
{
// comparison code using m_info
}
};
doSort()
{ std::sort( arr, arr+someSize, doCompare(*this) ); }
};
Usar un funtor siempre es mejor, solo que más tiempo para escribir (eso puede ser inconveniente pero bueno…)
Creo que también puede usar std::bind con la función miembro, pero no estoy seguro de cómo y eso no sería fácil de leer de todos modos.
ACTUALIZACIÓN 2014: hoy tenemos acceso a los compiladores c++ 11, por lo que podría usar una lambda en su lugar, el código sería más corto pero tendría exactamente la misma semántica.

Akim
La solución propuesta por Rob ahora es válida en C++ 11 (sin necesidad de Boost):
void doSort()
{
using namespace std::placeholders;
std::sort(arr, arr+someSize, std::bind(&MyClass::doCompare, this, _1, _2));
}
De hecho, como lo menciona Klaim, las lambdas son una opción, un poco más detallada (tienes que “repetir” que los argumentos son enteros):
void doSort()
{
std::sort(arr, arr+someSize, [this](int l, int r) {return doCompare(l, r); });
}
C ++ 14 admite auto
aquí:
void doSort()
{
std::sort(arr, arr+someSize, [this](auto l, auto r) {return doCompare(l, r); });
}
pero aún así, declaró que los argumentos se pasan por copia.
Entonces la pregunta es “cuál es el más eficiente”. Esa pregunta fue tratada por Travis Gockel: Lambda contra enlace. Su programa de referencia da en mi computadora (OS X i7)
Clang 3.5 GCC 4.9
lambda 1001 7000
bind 3716166405 2530142000
bound lambda 2438421993 1700834000
boost bind 2925777511 2529615000
boost bound lambda 2420710412 1683458000
donde lambda
es una lambda usada directamente, y lambda bound
es una lambda almacenada en un std::function
.
Por lo tanto, parece que las lambdas son una mejor opción, lo que no es una gran sorpresa ya que el compilador cuenta con información de mayor nivel de la que puede obtener ganancias.
Hay una manera de hacer lo que quieras, pero necesitas usar un pequeño adaptador. Como STL no lo escribe por usted, puede escribirlo usted mismo:
template <class Base, class T>
struct adaptor_t
{
typedef bool (Base::*method_t)(const T& t1, const T& t2));
adaptor_t(Base* b, method_t m)
: base(b), method(m)
{}
adaptor_t(const adaptor_t& copy) : base(copy.base), method(copy.method) {}
bool operator()(const T& t1, const T& t2) const {
return (base->*method)(t1, t2);
}
Base *base;
method_t method;
}
template <class Base, class T>
adaptor_t<Base,T> adapt_method(Base* b, typename adaptor_t<Base,T>::method_t m)
{ return adaptor_t<Base,T>(b,m); }
Entonces, puedes usarlo:
doSort() { std::sort(arr,arr+someSize, adapt_method(this, &doCompare)); }
El tercer argumento en el llamado de std::sort()
no es compatible con el puntero de función que necesita std::sort()
. Consulte mi respuesta a otra pregunta para obtener una explicación detallada de por qué la firma de una función miembro es diferente de una firma de función normal.

graham aser
Una forma muy sencilla de usar de manera efectiva una función miembro es usar operator<. Es decir, si tiene una función llamada compare, puede llamarla desde operator<. Aquí hay un ejemplo de trabajo:
class Qaz
{
public:
Qaz(int aX): x(aX) { }
bool operator<(const Qaz& aOther) const
{
return compare(*this,aOther);
}
static bool compare(const Qaz& aP,const Qaz& aQ)
{
return aP.x < aQ.x;
}
int x;
};
Entonces ni siquiera necesita dar el nombre de la función a std::sort:
std::vector<Qaz> q;
q.emplace_back(8);
q.emplace_back(1);
q.emplace_back(4);
q.emplace_back(7);
q.emplace_back(6);
q.emplace_back(0);
q.emplace_back(3);
std::sort(q.begin(),q.end());

sur
Actualizando la respuesta de Graham Asher, ya que no necesita la comparación pero puede usar el operador menos directamente.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Qaz {
public:
Qaz(int aX): x(aX) { }
bool operator<(const Qaz& aOther) const {
return x < aOther.x;
}
int x;
};
int main() {
std::vector<Qaz> q;
q.emplace_back(8);
q.emplace_back(1);
q.emplace_back(4);
q.emplace_back(7);
q.emplace_back(6);
q.emplace_back(0);
q.emplace_back(3);
std::sort(q.begin(),q.end());
for (auto& num : q)
std::cout << num.x << "\n";
char c;
std::cin >> c;
return 0;
}
Duplicado exacto de stackoverflow.com/q/639100/627163; sin embargo, esto aquí se plantea de una manera mucho más sucinta.
– Daniel
23 de noviembre de 2012 a las 20:03