¿Debo declarar una constante en lugar de escribir una función constexpr?

Resuelto Warren P asked hace 13 años • 15 respuestas

Me parece que tener una "función que siempre devuelve 5" es romper o diluir el significado de "llamar a una función". Debe haber una razón o una necesidad para esta capacidad o no estaría en C++ 11. ¿Por qué está ahí?

// preprocessor.
#define MEANING_OF_LIFE 42

// constants:
const int MeaningOfLife = 42;

// constexpr-function:
constexpr int MeaningOfLife () { return 42; }

Me parece que si escribiera una función que devuelve un valor literal y llegara a una revisión de código, alguien me diría que debería declarar un valor constante en lugar de escribir retorno 5.

Warren P avatar Jan 20 '11 21:01 Warren P
Aceptado

Supongamos que hace algo un poco más complicado.

constexpr int MeaningOfLife ( int a, int b ) { return a * b; }

const int meaningOfLife = MeaningOfLife( 6, 7 );

Ahora tiene algo que se puede evaluar hasta una constante manteniendo una buena legibilidad y permitiendo un procesamiento un poco más complejo que simplemente establecer una constante en un número.

Básicamente proporciona una buena ayuda para el mantenimiento a medida que resulta más obvio lo que estás haciendo. Toma max( a, b )por ejemplo:

template< typename Type > constexpr Type max( Type a, Type b ) { return a < b ? b : a; }

Es una elección bastante simple, pero significa que si llama maxcon valores constantes, se calcula explícitamente en tiempo de compilación y no en tiempo de ejecución.

Otro buen ejemplo sería una DegreesToRadiansfunción. Todo el mundo encuentra que los grados son más fáciles de leer que los radianes. Si bien quizás sepas que 180 grados es 3,14159265 (Pi) en radianes, es mucho más claro escribirlo de la siguiente manera:

const float oneeighty = DegreesToRadians( 180.0f );

Aquí hay mucha información útil:

http://en.cppreference.com/w/cpp/language/constexpr

Goz avatar Jan 20 '2011 14:01 Goz

Introducción

constexprno se introdujo como una forma de decirle a la implementación que algo se puede evaluar en un contexto que requiere una expresión constante ; Las implementaciones conformes han podido demostrar esto antes de C++ 11.

Algo que una implementación no puede probar es la intención de un determinado fragmento de código:

  • ¿Qué es lo que el desarrollador quiere expresar con esta entidad?
  • ¿Deberíamos permitir ciegamente que el código se use en una expresión constante , solo porque funciona?

¿Qué sería del mundo sin él constexpr?

Digamos que está desarrollando una biblioteca y se da cuenta de que desea poder calcular la suma de cada número entero en el intervalo (0,N].

int f (int n) {
  return n > 0 ? n + f (n-1) : n;
}

La falta de intención

Un compilador puede probar fácilmente que la función anterior se puede llamar en una expresión constante si el argumento pasado se conoce durante la traducción; pero no ha declarado esto como una intención; simplemente resultó ser el caso.

Ahora viene alguien más, lee su función, hace el mismo análisis que el compilador; "¡ Oh, esta función se puede utilizar en una expresión constante!" y escribe el siguiente fragmento de código.

T arr[f(10)]; // freakin' magic

la optimizacion

Usted, como desarrollador de biblioteca, decide que fdebe almacenar en caché el resultado cuando se invoca; ¿Quién querría calcular el mismo conjunto de valores una y otra vez?

int func (int n) { 
  static std::map<int, int> _cached;

  if (_cached.find (n) == _cached.end ()) 
    _cached[n] = n > 0 ? n + func (n-1) : n;

  return _cached[n];
}

El resultado

Al introducir su optimización, simplemente interrumpió cada uso de su función que se encontraba en un contexto donde se requería una expresión constante .

Nunca prometiste que la función fuera utilizable en una expresión constante , y sin constexprella no habría forma de cumplir dicha promesa.


Entonces, ¿por qué necesitamos constexpr?

El uso principal de constexpr es declarar intención .

Si una entidad no está marcada como constexpr, nunca estuvo destinada a usarse en una expresión constante ; e incluso si lo es, confiamos en el compilador para diagnosticar dicho contexto (porque ignora nuestra intención).

Filip Roséen - refp avatar Mar 02 '2015 23:03 Filip Roséen - refp

Tomar std::numeric_limits<T>::max(): por alguna razón, este es un método. constexprSería beneficioso aquí.

Otro ejemplo: desea declarar una matriz C (o una std::array) que sea tan grande como otra matriz. La forma de hacer esto en este momento es la siguiente:

int x[10];
int y[sizeof x / sizeof x[0]];

Pero, ¿no sería mejor poder escribir:

int y[size_of(x)];

Gracias a constexpr, puedes:

template <typename T, size_t N>
constexpr size_t size_of(T (&)[N]) {
    return N;
}
Konrad Rudolph avatar Jan 20 '2011 14:01 Konrad Rudolph

constexprLas funciones son realmente agradables y una gran adición a C++. Sin embargo, tiene razón en que la mayoría de los problemas que resuelve se pueden solucionar de manera poco elegante con macros.

Sin embargo, uno de los usos de constexprno tiene constantes escritas equivalentes en C++03.

// This is bad for obvious reasons.
#define ONE 1;

// This works most of the time but isn't fully typed.
enum { TWO = 2 };

// This doesn't compile
enum { pi = 3.1415f };

// This is a file local lvalue masquerading as a global
// rvalue.  It works most of the time.  But May subtly break
// with static initialization order issues, eg pi = 0 for some files.
static const float pi = 3.1415f;

// This is a true constant rvalue
constexpr float pi = 3.1415f;

// Haven't you always wanted to do this?
// constexpr std::string awesome = "oh yeah!!!";
// UPDATE: sadly std::string lacks a constexpr ctor

struct A
{
   static const int four = 4;
   static const int five = 5;
   constexpr int six = 6;
};

int main()
{
   &A::four; // linker error
   &A::six; // compiler error

   // EXTREMELY subtle linker error
   int i = rand()? A::four: A::five;
   // It not safe use static const class variables with the ternary operator!
}

//Adding this to any cpp file would fix the linker error.
//int A::four;
//int A::six;
deft_code avatar Jan 20 '2011 16:01 deft_code