c++ templates c++11 template-meta-programming typetraits

¿Por qué los rasgos de tipo C++ 11 no son plantillas de alias?



templates c++11 (3)

Pregunta similar: ¿Por qué se implementan type_traits con estructuras de plantillas especializadas en lugar de constexpr? - Pero con una respuesta diferente.

Me doy cuenta de que las plantillas de alias no pueden ser especializadas y, por lo tanto, no se pueden usar actualmente para implementar rasgos de tipo directamente 1 . Sin embargo, esta es una decisión consciente del comité y, por lo que veo, no hay ninguna razón técnica para prohibir esto.

Entonces, ¿no habría tenido más sentido implementar rasgos de tipo como plantillas de alias, simplificando su sintaxis?

Considerar

typename enable_if<is_pointer<T>::value, size_t>::type address(T p);

versus

enable_if<is_pointer<T>, size_t> address(T p);

Por supuesto, esto introduce un cambio de interfaz de última hora al pasar de Boost.TypeTraits , pero ¿es esto realmente un problema tan grande?

Después de todo, el código tendrá que modificarse de todos modos ya que los tipos residen en diferentes espacios de nombres y, dado que muchos programadores modernos de C ++ se muestran reacios a abrir espacios de nombres, se calificarán explícitamente (si es que se cambiarían).

Por otro lado, simplifica enormemente el código. Y dado que la metaprogramación de plantillas a menudo se vuelve profundamente anidada, compleja y compleja, parece obvio que una interfaz más clara es beneficiosa.

¿Me estoy perdiendo de algo? Si no, agradecería una respuesta que no sea una simple suposición, sino que se base en (y puede citar) el conocimiento de la lógica de decisión del comité.

1 ¡ Pero muy bien indirectamente! Considerar:

template <typename T> using is_pointer = typename meta::is_pointer<T>::type;

Donde meta::is_pointer<T> corresponde al tipo std::is_pointer<T> actual.


Como una nota al margen completa, ya que parece haber confusión sobre cómo los alias pueden o no pueden ayudar a un rasgo como std::is_pointer :

Puede ir a la ruta Boost.MPL y decidir que usará constantes integrales de estilo Boost.MPL, lo que significa tipos

template<typename Cond, typename Then = void> using enable_if = typename std::enable_if<Cond::value, Then>::type; // usage: template< typename T , typename = enable_if<std::is_pointer<T>> > size_t address(T p);

o puedes decidir usar valores en vez

template<bool Cond, typename Then> using enable_if = typename std::enable_if<Cond, Then>::type; // can use ::value template< typename T , typename = enable_if<std::is_pointer<T>::value>> > size_t address(T p); // or constexpr conversion operator template< typename T , typename = enable_if<std::is_pointer<T> {}> > size_t address(T p);

Tenga en cuenta que en el último caso no es posible usar enable_if<std::is_pointer<T>()> : std::is_pointer<T>() es un tipo de función ( void y devolver std::is_pointer<T> ) y no es válido ya que nuestro alias toma un valor y no un tipo en este caso. Las llaves aseguran que es una expresión constante en su lugar.

Como habrá notado, std::is_pointer no se beneficia de los alias de plantillas. Esto no es sorprendente, ya que es un rasgo en el que la parte interesante es acceder a ::value , no ::type : los alias de plantilla solo pueden ayudar con los tipos de miembros. El miembro de type de std::is_pointer no es interesante porque es una constante integral de estilo Boost.MPL (en este caso, std::true_type o std::false_type ), por lo que esto no nos ayuda. ¡Lo siento!


La respuesta más concreta a su pregunta es: nadie propuso hacerlo de esa manera.

El comité de estándares de C ++ es una colección de voluntarios multi-nacional, multi-corporación. Lo estás considerando como un comité de diseño dentro de una sola organización. El comité de estándares de C ++ literalmente no puede hacer nada sin una propuesta para incluir palabras en el borrador del estándar.

Me imagino que la razón por la que no hubo ninguna propuesta es que los rasgos de tipo fueron una propuesta temprana, con una implementación de impulso que se remonta a alrededor de 2000. Y los alias de las plantillas tardaron en implementarse. Muchos de los miembros del comité se muestran reacios a proponer algo que no han implementado. Y simplemente hubo poca oportunidad de implementar su propuesta.

Hubo mucha presión para enviar C ++ 11. Realmente estaba destinado a ser enviado en 2009 y cuando la fecha de envío se retrasó, fue muy difícil hacer algo al documento de trabajo, además de corregir las características que ya se estaban considerando. En algún momento tienes que poner grandes ideas nuevas en un segundo plano, para que nunca las envíes.

Actualizar

A partir de C ++ 14, los TransformationTraits (aquellos que resultan en un tipo) ahora tienen ortografía de alias de plantilla, por ejemplo:

template <bool b, class T = void> using enable_if_t = typename enable_if<b,T>::type;

Y el borrador de trabajo de C ++ 1z ahora tiene una plantilla de ortografía de variables para los rasgos que dan como resultado valores:

template <class T> constexpr bool is_pointer_v = is_pointer<T>::value;

Además, incluso en C ++ 11 se podría hacer:

typename enable_if<is_pointer<T>{}, size_t>::type address(T p);

Es decir, puede usar {} en lugar de ::value (suponiendo que su compilador tenga soporte constexpr ). En C ++ 14 que se convierte en:

enable_if_t<is_pointer<T>{}, size_t> address(T p);

Y en C ++ 1z:

enable_if_t<is_pointer_v<T>, size_t> address(T p);

Tenga en cuenta que la diferencia entre C ++ 1z y C ++ 14 es tan mínima que ni siquiera guarda caracteres, solo cambia {} a _v y cambia donde coloca estos dos caracteres.


Los rasgos de tipo, como muchas otras bibliotecas, incluyendo <memory> y <functional> , se heredaron de C ++ TR1. Aunque ese era un documento menos formal, era más formal que Boost, y la compatibilidad vale la pena.

Además, tenga en cuenta que los rasgos de tipo se derivan todos de std::integral_constant<bool> , que implementa una función de conversión constexpr a bool . Así que al menos guarda las partes de ::value , si así lo eliges.