Desde C++17 std::any
es presentado. Ahora se puede escribir código como este
#include <iostream>
#include <any>
#include <string>
int main () {
const double d = 1.2;
std::any var = d;
const std::string str = "Hello World";
var = str;
}
Se asigna un doble a la variable. var
y que un std::string
le fue asignado.
¿Por qué tiene std::any
sido introducido?
Creo que esto está violando la least astonishment rule
porque me resulta difícil pensar en una situación, donde esto se puede utilizar para expresar más claramente, lo que me gusta expresar.
¿Puede alguien darme un buen ejemplo, cuando std::any
es beneficioso
Cuándo usar
void*
como un patrón extremadamente inseguro con algunos casos de uso limitados, std::any
agrega seguridad de tipo, y es por eso que tiene algunos casos de uso reales.
Algunas posibilidades:
- En bibliotecas: cuando un tipo de biblioteca tiene que contener o pasar algo sin conocer el conjunto de tipos disponibles.
- Análisis de archivos: si realmente no puede especificar cuáles son los tipos admitidos.
- Paso de mensajes.
- Enlaces con un lenguaje de scripting.
- Implementación de un intérprete para un lenguaje de secuencias de comandos
- Interfaz de usuario: los controles pueden contener cualquier cosa
- Entidades en un editor
(árbitro)
-
“si realmente no puede especificar cuáles son los tipos admitidos”. Significa leer “cualquier cosa” en algún tipo de almacenamiento. DE ACUERDO. ¿Y cómo usar esos datos? Si no tengo idea de lo que contiene std::any, no tengo idea de cómo manejar esos datos. Y si sé cómo manejar los datos, conozco la lista de posibles tipos almacenados. Y eso es std::variant hecho para. No entiendo el punto… ¿puedes explicar un poco?
– Klaus
9 de octubre de 2018 a las 7:38
-
@Klaus si el código de análisis es genérico y es posible que no conozca todos los tipos como tiempo de compilación (o los tipos admitidos son dinámicos o no desea crear una dependencia).
– espectros
25 de julio de 2019 a las 0:00
-
“Implementación de un intérprete para un lenguaje de secuencias de comandos” es un muy buen ejemplo. Especialmente combinado con “Enlaces con un lenguaje de script“. Me pareció muy conveniente usar
std::any
al implementar un intérprete de Python restringido.– Furioso
31 de octubre de 2019 a las 10:04
-
@Klaus: El caso de uso es cuando alguno El código conoce el tipo que se almacena, pero ese código no es responsable de la toda la vida (incluyendo, quizás, hacer copias) de esos datos.
– Davis arenque
19 de diciembre de 2019 a las 8:12
bobá
Lo resumiría como el clásico “úsalo cuando no puedas evitarlo”.
Solo puedo pensar en implementaciones no críticas para el rendimiento de lenguajes de secuencias de comandos tipificados dinámicamente para representar variables del mundo de las secuencias de comandos, pero incluso eso con un tramo (Boost.Spirit/ejemplo/qi/compiler_tutorial lo hace sin, tanto para el analizador como para el tiempo de ejecución).
Para todo lo demás de los analizadores (por ejemplo, Impulsar.Espíritu.X3) a las API de la biblioteca (p. ej. ASIO) normalmente habría una alternativa más rápida/mejor/más específica, ya que muy pocas cosas son realmente “cualquier cosa”, la mayoría son más específicas que eso.
std::variant
y/ostd::optional
por “casi cualquier valor”std::packaged_task
/std::function
+ lambdas para “devolución de llamada con argumentos”, que sería un caso devoid*
en las API de C.- etc.
Específicamente, no lo conectaría a ciegas como reemplazo de un void*
ya que puede asignar memoria en el montón, lo que puede ser mortal para el código de alto rendimiento.
-
Puede, pero no tiene que hacerlo. La especificación permite la optimización de objetos pequeños IUC.
– StoryTeller – Unslander Mónica
9 de octubre de 2018 a las 7:39
-
@StoryTeller: actualicé la respuesta con un enlace a la pregunta dedicada a eso. Hay una respuesta allí con detalles por compilador. Por favor echa un vistazo.
– bobah
9 de octubre de 2018 a las 7:46
std::any
es un vocabulario tipo. Cuando necesite almacenar, bueno, un poco de cualquier cosa, como valor, puede usarlo.
Hay una serie de usos de “primer nivel”:
-
Al interactuar con lenguajes de secuencias de comandos que tienen tales tipos, es un ajuste natural.
-
Cuando tienes un árbol de propiedades con un contenido altamente polimórfico, y la estructura del árbol está desvinculada del productor y el consumidor del árbol.
-
Al reemplazar el equivalente de un
void*
fragmento de datos que pasa a través de una capa intermedia a la que realmente no le importa lo que transporta.
También se puede utilizar como bloque de construcción en otros casos. Por ejemplo, std::function
podría optar por almacenar su valor en el std::any
:
template<class R, class...Args>
struct func<R(Args...)> {
mutable std::any state;
R(*f)(std::any& state, Args&&...) = nullptr;
template<class T>
void bind(T&& t) {
state = std::forward<T>
f = [](std::any& state, Args&&...args)->R {
return std::any_cast<T&>(state)(std::forward<Args>(args)...);
};
}
R operator()(Args...args)const {
return f(state, std::forward<Args>(args)...);
}
};
esa es una implementación bastante pequeña de (la mayoría de) std::function
. Básicamente he usado any
para escribir borrar copiar/mover/destruir.
Puede usar esto en otros lugares para problemas similares (donde está escribiendo borrando alguna operación y también quiere escribir borrar copiar/mover/destruir), o generalizarlo.
-
tbh, este tipo no debería haber sido llamado
std::any
. Es..std::some(thing?)
– Swift – Pastel de viernes
06/01/2021 a las 21:40
-
@swift tendrás que discutir eso con… bueno, nadie, porque no va a cambiar. Pero definitivamente no yo.
– Yakk – Adam Nevraumont
6 de enero de 2021 a las 23:36
Se utiliza en Wt para proporcionar una interfaz sin plantilla para datos tabulados.
Hay conversiones a cadena para tipos incorporados y Wt, y puede registrar conversiones adicionales al especializarse Wt::any_traits
. Esto permite que cualquier cosa se muestre como una entrada en una tabla, las clases de vista no tienen que saber nada sobre los tipos que están mostrando.
blogs.msdn.microsoft.com/vcblog/2018/10/04/…
– CT
9 de octubre de 2018 a las 7:12
Si utiliza
std::any
para ofuscar el código, entonces asegúrese de que viola la regla del menor asombro. Si lo usas como un segurovoid*
(ver el artículo TC vinculado), es cualquier cosa menos sorprendente.– StoryTeller – Unslander Mónica
9 de octubre de 2018 a las 7:13
usar
std::any
donde en el pasado hubieras usadovoid*
. Es decir, idealmente, casi en ninguna parte.-Richard Hodges
9 de octubre de 2018 a las 7:16
open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3804.html
– Werner Henze
9 de octubre de 2018 a las 7:24
¿Será bueno junto con el patrón de fábrica?
– seccpur
9 de octubre de 2018 a las 7:36