suma propiedad para niños ley ejercicios ejemplos distributiva dela definicion conmutativa asociativa c++ templates metaprogramming

c++ - ley - propiedad conmutativa dela suma ejemplos para niños



Reducir la duplicación de código mientras se define una operación conmutativa (3)

Tengo un conjunto de sobrecargas de una función binaria conmutativa llamada overlap , que acepta dos tipos distintos:

class A a; class B b; bool overlap(A, B); bool overlap(B, A);

Mi overlap funciones devuelve verdadero si y solo si una forma se superpone a la otra; este es un ejemplo común que se usa cuando se analizan los multimethods .

Debido a que la overlap(a, b) es equivalente a la overlap(b, a) , solo necesito implementar un "lado" de la relación. Una solución repetitiva es escribir algo como esto:

bool overlap(A a, B b) { /* check for overlap */ } bool overlap(B b, A a) { return overlap(a, b); }

¡Pero preferiría no escribir un N! / 2 adicional N! / 2 N! / 2 versiones triviales de la misma función al permitir que se generen en su lugar, utilizando una plantilla.

template <typename T, typename U> bool overlap(T&& t, U&& u) { return overlap(std::forward<U>(u), std::forward<T>(t)); }

Desafortunadamente, esto es propenso a recurrir infinitamente, lo que no es aceptable: ver http://coliru.stacked-crooked.com/a/20851835593bd557

¿Cómo puedo evitar semejante recursión infinita? ¿Me estoy acercando al problema correctamente?


Aquí hay una solución simple:

template <typename T, typename U> void overlap(T t, U u) { void overlap(U, T); overlap(u, t); }

La plantilla en sí misma declara la función objetivo, que será preferible a la recursividad porque es una coincidencia exacta (asegúrese de ocuparse de la constness y la referencia en su caso real). Si la función no se ha implementado, se obtiene un error del enlazador:

/tmp/cc7zinK8.o: In function `void overlap<C, D>(C, D)'': main.cpp:(.text._Z7overlapI1C1DEvT_T0_[_Z7overlapI1C1DEvT_T0_]+0x20): undefined reference to `overlap(D, C)'' collect2: error: ld returned 1 exit status

... que apunta directamente a la función que falta :)


Como dijo un hombre sabio, no hay problema que no puedas resolver con una capa adicional de indirección, excepto demasiadas capas de indirección.

Por lo tanto, use SFINAE y algunos indirectos para hacerlo:

template<class A, class B> auto overlap(A&& a, B&& b) -> decltype(overlap_impl(''/0'', std::forward<A>(a), std::forward<B>(b))) { return overlap_impl(''/0'', std::forward<A>(a), std::forward<B>(b)); } template<class A, class B> auto overlap_impl(int, A&& a, B&& b) -> decltype(do_overlap(std::forward<A>(a), std::forward<B>(b))) { return do_overlap(std::forward<A>(a), std::forward<B>(b)); } template<class A, class B> auto overlap_impl(long, B&& b, A&& a) -> decltype(do_overlap(std::forward<A>(a), std::forward<B>(b))) { return do_overlap(std::forward<A>(a), std::forward<B>(b)); } // You can provide more choices if you want, for example to use member-functions. // Implement `do_overlap(A, B)`, maybe with references, in at least one direction.


Puede cambiar el nombre del método real a algo como overlap_impl y llamar a este dentro de la plantilla. Romperé la recursión:

bool overlap_impl(A a, B b) { /* check for overlap */ } template <typename T, typename U> bool overlap(T&& t, U&& u) { return overlap_impl(std::forward<U>(u), std::forward<T>(t)); } template<> bool overlap(A&& t, B&& u) { return overlap_impl(std::forward<A>(t), std::forward<B>(u)); }