Pregunta cómo proporcionar una función de intercambio para mi clase?


¿Cuál es la forma correcta de habilitar mi swap en algoritmos STL?

1) Miembro swap. Hace std::swap usa el truco SFINAE para usar el miembro swap.

2) De pie libre swap en el mismo espacio de nombres

3) Especialización parcial de std::swap.

4) Todo lo anterior.

Gracias.

EDITAR: Parece que no dije mi pregunta claramente. Básicamente, tengo una clase de plantilla y necesito algos de STL para usar el método de intercambio (eficiente) que escribí para esa clase.


75
2018-06-17 02:51


origen


Respuestas:


1) es el adecuado utilizar de swap. Escríbelo de esta manera cuando escribes código de "biblioteca" y quieres habilitar ADL (búsqueda dependiente de argumentos) en swap. Además, esto no tiene nada que ver con SFINAE.

// some algorithm in your code
template<class T>
void foo(T& lhs, T& rhs){
  using std::swap; // enable 'std::swap' to be found
                   // if no other 'swap' is found through ADL
  // some code ...
  swap(lhs, rhs); // unqualified call, uses ADL and finds a fitting 'swap'
                  // or falls back on 'std::swap'
  // more code ...
}

2) Es la forma correcta de proporcionar un swap función para su clase.

namespace Foo{

class Bar{}; // dummy

void swap(Bar& lhs, Bar& rhs){
  // ...
}

}

Si swap ahora se usa como se muestra en 1), se encontrará su función. Además, puede hacer que esa función sea un amigo si es absolutamente necesario o proporcionar un miembro swap eso es llamado por la función libre:

// version 1
class Bar{
public:
  friend void swap(Bar& lhs, Bar& rhs){
    // ....
  }
};

// version 2
class Bar{
public:
  void swap(Bar& other){
    // ...
  }
};

void swap(Bar& lhs, Bar& rhs){
  lhs.swap(rhs);
}

3) Te refieres a una especialización explícita. Parcial es todavía algo más y tampoco es posible para funciones, solo estructuras / clases. Como tal, ya que no puedes especializarte std::swap para las clases de plantilla, tener para proporcionar una función gratuita en su espacio de nombres. No es algo malo, si se me permite decirlo. Ahora, también es posible una especialización explícita, pero en general no desea especializar una plantilla de función:

namespace std
{  // only allowed to extend namespace std with specializations

template<> // specialization
void swap<Bar>(Bar& lhs, Bar& rhs){
  // ...
}

}

4) No, ya que 1) es distinto de 2) y 3). Además, tener ambos 2) y 3) llevará a tener siempre 2) elegido, porque encaja mejor.


84
2018-06-17 02:54



Para responder al EDIT, donde las clases pueden ser clases de plantilla, no necesita especialización en absoluto. considere una clase como esta:

template <class T>
struct vec3
{
    T x,y,z;
};

usted puede definir clases tales como:

vec3<float> a;
vec3<double> b;
vec3<int> c;

si desea poder crear una función para implementar los 3 intercambios (no es que esta clase de ejemplo lo amerite), simplemente desea que Xeo lo diga en (2) ... sin especialización, sino que simplemente realice una función de plantilla regular:

template <class T>
void swap(vec3<T> &a, vec3<T> &b)
{
    using std::swap;
    swap(a.x,b.x);
    swap(a.y,b.y);
    swap(a.z,b.z);
}

La función de plantilla de intercambio debe estar ubicada en el mismo espacio de nombres que la clase que está tratando de intercambiar. el siguiente método encontrará y usará ese intercambio aunque no esté haciendo referencia a ese espacio de nombres con ADL:

using std::swap;
swap(a,b);

1
2017-12-15 01:28