una simplex restricciones qué minimizar metodo maximizar lenguaje hungaro grafico función entre diferencia con codigo c++ c++14 restrict strict-aliasing

simplex - ¿Se puede emular la palabra clave de restricción de C utilizando un alias estricto en C++?



qué es maximizar y minimizar una función (5)

Creo que su solución no logra completamente el objetivo previsto, incluso si la UB no existiera. Después de todo, todos los accesos de datos reales se producen en el nivel de tipo incorporado. Si decltype(a->i) es int y su función manipula los punteros int* , en ciertas circunstancias, el compilador todavía debe asumir que esos punteros podrían ser alias a->i .

Ejemplo:

int func(noalias<S, 1> a) { int s = 0; int* p = getPtr(); for ( int i = 0; i < 10; ++i ) { ++*p; s += a->i; } return s; }

El uso de noalias difícilmente permitirá la optimización de la función anterior a lo siguiente:

int func(noalias<S, 1> a) { *getPtr() += 10; return 10 * a->i; }

Mi sensación es que la restrict no puede ser emulada, y debe ser soportada directamente por el compilador.

El problema

Falta la palabra clave de restrict en C en C ++, por lo que, por interés, estaba buscando una manera de emular la misma característica en C ++.

Específicamente, me gustaría que lo siguiente sea equivalente:

// C void func(S *restrict a, S *restrict b) // C++ void func(noalias<S, 1> a, noalias<S, 2> b)

donde noalias<T, n>

  • se comporta como T* cuando se accede con -> y *
  • se puede construir a partir de una T* (de modo que la función se puede llamar como func(t1, t2) , donde t1 y t2 son de tipo T* )
  • el índice n especifica la "clase de aliasing" de la variable, de modo que las variables de tipo noalias<T, n> y noalias<T, m> nunca se deben asumir como alias para n! = m.

Un intento

Aquí está mi solución profundamente defectuosa:

template <typename T, int n> class noalias { struct T2 : T {}; T *t; public: noalias(T *t_) : t(t_) {} T2 *operator->() const {return static_cast<T2*>(t);} // <-- UB };

Cuando se accede con -> , noalias<T, n>::T2* T* almacenado internamente en un noalias<T, n>::T2* y lo devuelve en su lugar. Dado que este es un tipo diferente para cada n , la regla de alias estricta garantiza que nunca serán alias. Además, dado que T2 deriva de T , el puntero devuelto se comporta como un T* . ¡Genial!

Aún mejor, el código se compila y la salida del ensamblaje confirma que tiene el efecto deseado.

El problema es el static_cast . Si t estuviera realmente apuntando a un objeto de tipo T2 entonces esto estaría bien. Pero t apunta a una T así que esto es UB. En la práctica, dado que T2 es una subclase que no agrega nada extra a T , probablemente tendrá el mismo diseño de datos, por lo que los accesos de miembros en T2* buscarán miembros con las mismas compensaciones que ocurren en T y todo estará bien.

Pero tener una clase dependiente de n es necesario para un alias estricto, y que esta clase se deriva de T también es necesario para que el puntero se pueda tratar como una T* . Así que UB parece inevitable.

Preguntas

  • ¿Se puede hacer esto en c ++ 14 sin invocar UB, posiblemente utilizando una idea completamente diferente?

  • Si no es así, entonces he oído hablar de un "operador de punto" en c ++ 1z; ¿Sería posible con esto?

  • Si lo anterior, ¿aparecerá algo similar a noalias en la biblioteca estándar?


La forma correcta de agregar semánticas de tipo restringido a C ++ sería hacer que el Estándar defina plantillas para referencias restringidas y punteros restringidos de tal manera que las versiones ficticias que funcionan como referencias ordinarias y punteros puedan codificarse en C ++. Si bien podría ser posible generar plantillas que se comporten como se requiere en todos los casos definidos, e invocar UB en todos los casos que no deberían definirse, hacerlo será inútil, si no contraproducente, a menos que un compilador esté programado para explotar la UB en cuestión para facilitar tales optimizaciones. Programar un compilador para explotar tales optimizaciones en los casos en que el código utiliza un tipo definido por el Estándar que existe para ese propósito es más fácil y más efectivo que tratar de identificar patrones dentro de los tipos de usuarios donde sería explotable, y también sería menos probable Tener efectos secundarios no deseados.


Podría usar la extensión __restrict__ GCC para __restrict__ / aliasing.

De los docs

Además de permitir punteros restringidos, puede especificar referencias restringidas, que indican que la referencia no tiene un alias en el contexto local.

void fn (int *__restrict__ rptr, int &__restrict__ rref) { /* ... */ }

En el cuerpo de fn , rptr apunta a un entero sin polarizar y rref se refiere a un entero sin polarizar (diferente). También puede especificar si el puntero de una función miembro no está igualado al usar __restrict__ como un calificador de función miembro.

void T::fn () __restrict__ { /* ... */ }

Dentro del cuerpo de T::fn , esto tendrá la definición efectiva T *__restrict__ const this . Observe que la interpretación de un calificador de función miembro __restrict__ es diferente a la de un calificador const o volatile , en el sentido de que se aplica al puntero en lugar del objeto. Esto es consistente con otros compiladores que implementan punteros restringidos.

Al igual que con todos los calificadores de parámetros más externos, __restrict__ se ignora en la coincidencia de definición de función. Esto significa que solo necesita especificar __restrict__ en una definición de función, en lugar de en un prototipo de función también.


Si solo estamos hablando de una solución estándar pura de C ++, la verificación del tiempo de ejecución es la única manera. De hecho, ni siquiera estoy seguro de si esto es posible dada la fuerza en la definición del calificador de valor de restricción de C, que es que solo se puede acceder al objeto con el puntero de restricción.


Tal vez no entiendo tu pregunta, pero la palabra clave de restricción c se eliminó de STANDARD C ++, pero casi cada compilador tiene sus equivalentes de "restricción de C":

Microsoft VS tiene __declspec (restringir): https://msdn.microsoft.com/en-us/library/8bcxafdh.aspx

y GCC tiene __ restrict__: https://gcc.gnu.org/onlinedocs/gcc/Restricted-Pointers.html

Si quieres una definición común puedes usar # define''s

#if defined(_MSC_VER) #define RESTRICT __declspec(restrict) #else #define RESTRICT __restrict__ #endif

No lo pruebo, hágamelo saber es que no funciona.