Pregunta Operador de asignación de copia de sobrecarga para una estructura miembro de una estructura de plantilla sin tipo


Tengo la siguiente plantilla sin tipo:

template<size_t MAX_SIZE>
struct Path{
    struct Point{
        float x;
        float y;
       }
    };
    Point segment[MAX_SIZE];
};

Si ahora declaro dos rutas diferentes, no puedo asignar elementos de los diferentes segmentos entre sí, ya que las estructuras pueden tener la misma estructura, pero son de tipo diferente:

Path<10> path_a ;
Path<30> path_b ;
path_a.segment[0].x = 1;
path_a.segment[0].y = 2;
path_b.segment[0] = path_a.segment[0]; // <- error C2679 in Visual Studio)

Por supuesto, si separa la definición de Punto y Ruta, la asignación funcionaría:

struct Point{
        float x;
        float y;
       };

template<size_t MAX_SIZE>
struct Path{
    Point segment[MAX_SIZE];
};

Pero eso no es lo que quiero (esto es solo un MWE), así que me preguntaba cómo puedo sobrecargar el operador de asignación de copias para que funcione. He probado numerosas variantes, por ejemplo:

template<size_t MAX_SIZE>
struct Path{
    struct Point{
        float x;
        float y;
        template<size_t OTHER_SIZE>
        Point & operator = (const typename Path<OTHER_SIZE>::Point & that)
        {
            x = that.x;
            y = that.y;
            return *this;
        }
    };
    Point segment[MAX_SIZE];
};

pero siempre obtengo el mismo error. Entonces mi pregunta es: ¿es posible sobrecargar = de una manera que permita una asignación del siguiente formulario sin cambiar el diseño de mis estructuras?

path_b.segment[0] = path_a.segment[0];

9
2018-04-06 14:38


origen


Respuestas:


Sí, tal configuración es posible. En el núcleo, necesita una plantilla de operador de asignación que aceptará todos los tipos:

template<class T>
Point & operator = (const T & that)

Como solución básica, esto sería suficiente. Ahora funcionará con todos los tipos que tienen miembros x y y de tipos compatibles, y produce un mensaje de error (generalmente) feo para los tipos que no lo hacen.

Si eso es lo suficientemente bueno para ti, hemos terminado.

Si tiene otras sobrecargas del operador de asignación, probablemente desee deshabilitar selectivamente la plantilla. Para esto, necesitarás instrumentar el Point clases y uso SFINAE:

template<size_t MAX_SIZE>
struct Path{
    struct Point{
        float x;
        float y;
        struct EnableAssignment {};
    };
    Point segment[MAX_SIZE];
};

La instrumentación se usa así:

template<class T, class U = typename T::EnableAssignment>
Point & operator = (const T & that)

[Ejemplo en vivo simplificado]


El código anterior utiliza un argumento de plantilla predeterminado en una plantilla de función, que solo se introdujo en C ++ 11. Antes de eso, tendrías que invocar a SFINAE de alguna otra forma:

template <class L, class R>
struct SfinaeThenRight
{
  typedef R type;
};

template <class T>
typename SfinaeThenRight<typename T::EnableAssignment, Point&>::type operator = (const T & that)

[Simplified C ++ 98 live example]


5
2018-04-06 14:54



template<size_t OTHER_SIZE>
Point & operator = (const typename Path<OTHER_SIZE>::Point & that)

no funcionará porque el argumento de la plantilla OTHER_SIZE en la estructura externa no se puede deducir. Tu puedes sólo:

template<typename T>
Point & operator = (const T & that)
{
    x = that.x;
    y = that.y;
    return *this;
}

Tenga en cuenta que si algo sin miembro x y y Al pasar, obtendrás un error de compilación, que debería ser suficiente para este caso.

VIVIR


2
2018-04-06 14:51