Instancias redundantes en expresiones constantes booleanas

tengo un n-cualquier booleano OR función de tiempo de ejecución any_run

#include <assert.h>

bool any_run() { return false; }

template <typename... B>
bool any_run(bool a, B... b)
{
    assert(a);
    return a || any_run(b...);
}

así como un análogo en tiempo de compilación any_comp

#include <type_traits>

template <bool E>
using expr = std::integral_constant <bool, E>;

using _true  = expr <true>;
using _false = expr <false>;

template <typename... A>
struct any_comp : public _false { };

template <typename A, typename... B>
struct any_comp <A, B...> : public expr <A() || any_comp <B...>()>
{
    static_assert(A(), "");
};

ambos contienen aserciones (en tiempo de ejecución o en tiempo de compilación, respectivamente) para garantizar que el primer argumento sea verdadero.

Ahora dando la siguiente entrada

int main()
{
    any_run   (true,  false,  false);
    any_comp <_true, _false, _false>();
}

la aserción en tiempo de ejecución nunca falla, pero la de tiempo de compilación sí. Esto significa que any_run(false, false) nunca se llama, sin embargo any_comp <_false, _false> se instancia, a pesar del hecho de que la expresión constante booleana

A() || any_comp <B...>()

podría ser evaluado para true if A() == true sin instanciar nunca any_comp <B...>.

Mi pregunta es si este experimento y su conclusión son válidos, y qué diría la norma al respecto.

Es importante porque si la conclusión es válida, tendría que volver a implementar varias funciones en tiempo de compilación con más cuidado (con más especializaciones) para que la compilación sea más rápida, aunque generalmente prefiero mantener las cosas lo más simples posible.

preguntado el 21 de septiembre de 13 a las 12:09

1 Respuestas

El cortocircuito solo funciona en el nivel de tiempo de ejecución para ||. En tiempo de compilación, necesita algo más como:

#include <type_traits>

template <typename T, typename U>
struct integral_or : U { };

template <typename U>
struct integral_or <std::true_type, U> : std::true_type { };

template <typename... A>
struct any_comp : std::false_type { };

template <typename A, typename... B>
struct any_comp <A, B...> : integral_or <A, any_comp <B...>>
{
    static_assert(A(), "");
};

int main()
{
    any_comp <std::true_type, std::false_type, std::false_type>();
}

Respondido el 21 de Septiembre de 13 a las 12:09

Correcto... y estamos (casi) de regreso a C++03... Y estaba tan feliz de deshacerme de todas esas funciones como integral_and que hacen todo tan ilegible cuando ocurren expresiones más complejas. ¡Gracias! - iavr

También podría sobrecargar los operadores booleanos para implementar plantillas de expresión y proporcionar una sintaxis más clara ( decltype( a() || b() && c() ) por ejemplo. Me gusta este - Manu343726

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.