skypjack
Esta es quizás una pregunta básica, pero no puedo ver la respuesta por mí mismo en este momento.
Considere el siguiente código:
template<bool b>
struct T {
static constexpr int value = (b ? 42 : 0);
};
template<bool b>
struct U {
enum { value = (b ? 42 : 0) };
};
int main() {
static_assert(T<true>::value == 42, "!");
static_assert(T<false>::value == 0, "!");
static_assert(U<true>::value == 42, "!");
static_assert(U<false>::value == 0, "!");
}
Estoy acostumbrado a usar estructuras como T
pero más de una vez he visto estructuras como U
utilizado para el mismo propósito (principalmente definición de rasgos).
Por lo que puedo ver, ambos se resuelven en tiempo de compilación y resuelven casi el mismo problema, pero me parece que T
es mucho más legible que U
(bueno, lo sé, mi opinión personal).
Mi pregunta es bastante simple: ¿hay alguna razón técnica por la cual una solución sea mejor que la otra?
Es más, ¿existe algún caso para el cual alguno de ellos no sea una solución viable?
sergeya
Tenga en cuenta que la respuesta a continuación no se aplica a C++ 17 y versiones posteriores.
No habrá una diferencia notable para las constantes integrales cuando se usen así.
Sin embargo, enum
en realidad es mejor, porque es una verdadera constante con nombre. constexpr
constante integral es un objeto que puede ser, por ejemplo, ODR-usado – y eso daría lugar a errores de vinculación.
#include <iostream>
struct T {
static constexpr int i = 42;
enum : int {x = 42};
};
void check(const int& z) {
std::cout << "Check: " << z << "\n";
}
int main() {
// check(T::i); // Uncommenting this will lead to link error
check(T::x);
}
Cuándo check(T::i)
no está comentado, el programa no se puede vincular:
/tmp/ccZoETx7.o
: En función `main
‘:ccc.cpp
🙁.text+0x45
): referencia indefinida a `T::i
‘collect2
: error:ld
devuelto1
estado de salida
Sin embargo, el verdadero enum
siempre funciona
-
Puede solucionar el problema creando una instancia
i
en un archivo cpp, pero eso le permite tomar la dirección de&
. Tomar la dirección de un valor no tiene sentido. Las enumeraciones no permiten esto.– Pato mugido
16 mayo 2016 a las 20:19
-
@gzlbg
inline
¿variable? Nunca he oído hablar de ellos. ¿Tienes un enlace? Gracias.– skypjack
18 mayo 2016 a las 9:50
-
-
@SergeyA, “Si un programa contiene una violación de una regla para la cual no se requiere diagnóstico, esta Norma Internacional no establece ningún requisito sobre las implementaciones con respecto a ese programa”.
– ixSci
19 mayo 2016 a las 13:43
R Sahú
Sospecho que es código heredado.
enum { value = (b ? 42 : 0) };
es un código válido tanto en C++03 como en C++11.
static constexpr int value = (b ? 42 : 0);
solo es válido en C++11.
Es más, ¿existe algún caso para el cual alguno de ellos no sea una solución viable?
Ambas son soluciones viables en C++11. La elección de cuál usar depende de un equipo. Va a ser una cuestión de decisión política.
Como indica la respuesta de SergeyA, enum
son verdaderas constantes. No puede usar ODR. Puede usar ODR constexpr
. Dependiendo de cuál de estos es deseable para su aplicación, puede decidir si usar enum
s o constexpr
s.
-
Tiene sentido y sospecho casi lo mismo. He preguntado en SO con respecto a oscuras razones técnicas porque no estoy seguro de eso, eso es todo. 🙂
– skypjack
16 mayo 2016 a las 17:38
-
@skypjack, esperemos que alguien tenga más información.
– R Sahu
16 mayo 2016 a las 17:41
-
Hay un beneficio en el uso de enumeración, vea mi respuesta.
– SergeyA
16 mayo 2016 a las 17:41
-
@RSahu, dudo que haya un caso en el que alguien quiere a ODR-use un
constexpr
. Esto generalmente no es deseado.– SergeyA
16 mayo 2016 a las 17:53
-
@SergeyA, no estoy dispuesto a apostar en contra de eso. He visto a los desarrolladores hacer algunas locuras.
– R Sahu
16 mayo 2016 a las 17:55
La respuesta actualmente aceptada por SergeyA ya no es válida a partir de C++17 (Definiciones y ODR).
Cada declaración es una definición, excepto por lo siguiente:
- …
- (Obsoleto) Declaración de ámbito de espacio de nombres de un miembro de datos estáticos que se definió dentro de la clase con el especificador constexpr
struct S {
static constexpr int x = 42; // implicitly inline, defines S::x
};
constexpr int S::x; // declares S::x, not a redefinition
Por lo tanto, a partir de C ++ 17, usaría la definición estática constexpr que es más expresiva que la enumeración.
Si estuviera usando algo más que integrales, entonces TENDRÁ que usar constexpr.
– Edward Extraño
16 mayo 2016 a las 17:48
@CrazyEddie ¡Esto es bastante obvio! El ejemplo no está ahí para un error. 🙂
– skypjack
16 mayo 2016 a las 18:17
Me gustaría saber las razones de los votantes negativos y los que votaron para cerrar la pregunta como basada principalmente en la opinión, con una respuesta tan técnica publicada por @SergeyA (como se señaló correctamente en la pregunta por sus partes técnicas, de hecho) . Bastante gracioso.
– skypjack
16 mayo 2016 a las 19:18