que library libboost compiler c++ boost c++11 c++-concepts

libboost - ¿Cuál es la diferencia entre los conceptos de C++ 0x y The Boost Concept Check Library(BCCL)?



c++17 (3)

Los conceptos no hicieron el estándar C ++ 0x, pero Boost aún proporciona la biblioteca de verificación de conceptos de Boost (BCCL) . Supongo que BCCL no cubre todo lo que estaba previsto en el estándar C ++ 0x. ¿Cuál es la diferencia entre BCCL y la solución propuesta de C ++ 0x?


Comprobando la definición de la plantilla

Una gran diferencia de conceptos con respecto a estas soluciones manuales es que los conceptos permiten la verificación de tipo de una plantilla sin hacer nada especial. La biblioteca de verificación de concepto permite solo el uso de la misma para ser revisado por tipo. Ejemplo:

template<typename InputIterator> int distance(InputIterator a, InputIterator b) { return b - a; }

Ahora puede rociar esa plantilla con controles conceptuales y rasgos, pero nunca recibirá un error después de escribir esa plantilla, porque el Estándar permite que el compilador demore la compilación de la plantilla hasta que se cree una instancia. Para verificar, debe escribir clases de "arquetipo", que contienen exactamente aquellas operaciones que requiere la interfaz y luego crearlas de forma artificial.

Leyendo la documentación de BCCL, encontré que ya incluye los arquetipos comunes como "constructible por defecto". Pero si escribe sus propios conceptos, también tendrá que proporcionar sus propios arquetipos, lo cual no es fácil (debe encontrar exactamente la funcionalidad mínima que debe proporcionar un tipo). Por ejemplo, si su arquetipo contiene un operator- , entonces la prueba de su plantilla con ese arquetipo (incorrecto) tendrá éxito, aunque los conceptos no requieren tal operador.

La propuesta de conceptos rechazados crea automáticamente los arquetipos para usted, en función de los requisitos que se especificaron y que estaban implícitos (un puntero tipo T* utilizado en un parámetro implicará el requisito PointeeType para T , por ejemplo). No tiene que preocuparse por estas cosas, excepto, por supuesto, cuando la definición de su plantilla contiene un error de tipo.

Comprobación de los requisitos semánticos.

Considere este código, usando verificaciones de conceptos hipotéticos.

template<ForwardIterator I> void f(I a, I b) { // loop two times! loopOverAToB(a, b); loopOverAToB(a, b); }

El manual de BCCL dice que los requisitos semánticos no están marcados. Sólo se verifican los requisitos y tipos de sintaxis. Considere un iterador hacia adelante: existe el requisito semántico de que puede usarlo en algoritmos de paso múltiple. La comprobación de sintaxis solo no podrá probar este requisito (piense en lo que sucede si un iterador de flujo pasaría accidentalmente esa comprobación)

En la propuesta rechazada, tenía que colocar explícitamente auto delante de las definiciones del concepto para que el compilador fuera exitoso después de la comprobación de la sintaxis. Si no se especificaba auto , entonces un tipo explícitamente tenía que definir un mapa conceptual para decir que es compatible con ese concepto. Por lo tanto, nunca se tomaría un iterador de flujo para pasar una verificación ForwardIterator.

Sintaxis remapping

Esta fue otra característica. Una plantilla como

template<InputIterator I> requires OutputStreamable<I::value_type> void f(I a, I b) { while(a != b) std::cout << *a++ << " "; }

Se puede usar de la siguiente manera, si el usuario proporcionara un mapa conceptual que le enseñe al compilador cómo desreferenciar un entero, y por lo tanto cómo un entero satisface el concepto de InputIterator.

f(1, 10);

Este es el beneficio de una solución basada en lenguaje, y creo que BCCL no puede resolverlo nunca.

Sobrecarga basada en conceptos

En una lectura rápida de BCCL, tampoco puedo detectar nada que permita que esto suceda. Un error de coincidencia de concepto parece causar un error de compilación difícil. La propuesta rechazada permite lo siguiente:

template<ForwardIterator I> I::difference_type distance(I a, I b) { I::difference_type d = 0; while(a != b) ++a, ++d; return d; } template<RandomAccessIterator I> I::difference_type distance(I a, I b) { return b - a; }

Si se pudiera usar un tipo con ambas plantillas, entonces se usaría la segunda plantilla, porque es más especializada: RandomAccessIterator refina el concepto ForwardIterator .


Descargo de responsabilidad: no pude usar BCCL con éxito en los últimos 30 minutos a pesar de que ya tenía instalado Boost. El ejemplo que ve a continuación se ve bien de acuerdo con la documentación BCCL de Boost 1.37 pero no funcionó. Supongo que esto cuenta como desventaja.

Con BCCL solo obtiene algo como aserciones estáticas, mientras que la función de concepto de lenguaje central proporciona una verificación de tipo modular completa y es capaz de evitar que alguna plantilla de función participe en la resolución de sobrecarga. Con los conceptos nativos, el compilador puede verificar inmediatamente el cuerpo de una plantilla restringida, mientras que BCCL no hace que el compilador verifique nada al respecto. Tiene que crear una instancia manual de su plantilla con los parámetros de "tipo de arche" para ver si la plantilla utiliza alguna operación que no esté disponible (por ejemplo, operador, en los iteradores hacia adelante).

En cuanto a la resolución de sobrecarga aquí hay un ejemplo:

template<typename Iter> void foo(Iter,Iter) { BOOST_CONCEPT_ASSERT((RandomAccessIterator<Iter>)); } void foo(long, int); int main() { foo(2,3); // compile-time error }

La plantilla es una mejor coincidencia porque la no plantilla requiere una conversión de int a long. Pero la creación de instancias falla porque int no es un iterador. Recibes un buen mensaje de error que lo explica, pero eso no es muy satisfactorio, ¿verdad? Con conceptos nativos podrías haber escrito.

template<typename Iter> requires RandomAccessIterator<Iter> void foo(Iter,Iter) {} void foo(long, int); int main() { foo(2,3); // OK, picks non-template foo }

Aquí, la plantilla de función no participará en la resolución de sobrecarga porque el requisito para T = int no se cumple. ¡Genial!

Todavía podemos restringir las plantillas de función con el truco de SFINAE. C ++ 0x extiende SFINAE a las expresiones y junto con decltype y los argumentos de plantilla predeterminados para las plantillas de función que podemos escribir

template<typename T> T&& make(); template<typename Iter, class = decltype( *make<Iter>() )> void foo(Iter,Iter) {} void foo(long, int); int main() { foo(2,3); // OK, picks non-template foo }

En este caso, la deducción de argumentos de la plantilla fallará silenciosamente porque el compilador no sabe qué tipo de expresión se supone que <Iter> () es (no podemos hacer referencia a un int). Con un poco de metaprogramación de plantillas y algunas macros, podemos acercarnos bastante a la imposición de restricciones estructurales arbitrarias en los parámetros de la plantilla de forma legible . Esto es lo que podría parecer asumiendo las definiciones apropiadas para REQUIRES y RandomAccessIterator:

template <typename Iter REQUIRES( RandomAccessIterator<Iter> ) > void foo(Iter,Iter) {}

HTH, S


La característica del concepto C ++ 0x sería una característica del lenguaje central , cuyo proceso completo sería realizado por el compilador.

La biblioteca Boost Concept Check es casi la misma función pero escrita en C ++ y macro como una biblioteca para simular algunas de las funciones. No puede hacer todo lo que se requeriría en la función de idioma final (dependiendo de la definición de la función final), pero proporciona algunas soluciones equivalentes para la comprobación del tipo de plantilla (y otras comprobaciones de tiempo de compilación).

Como se sugirió, dado que el concepto C ++ 0x es una característica del lenguaje, permitiría proporcionar una semántica más elegante y permitir que el compilador utilice información que actualmente no está disponible para el programa, permitiendo errores más detallados o inteligentes en el momento de la compilación (como el concepto primero el propósito es permitir la verificación de tipo abstracto en las plantillas).