¿Qué es decltype con dos argumentos?


Editar, para evitar confusiones: decltypeno acepta dos argumentos. Ver respuestas.

Las siguientes dos estructuras se pueden usar para verificar la existencia de una función miembro en un tipo T durante el tiempo de compilación:

// Non-templated helper struct:
struct _test_has_foo {
    template<class T>
    static auto test(T* p) -> decltype(p->foo(), std::true_type());

    template<class>
    static auto test(...) -> std::false_type;
};

// Templated actual struct:
template<class T>
struct has_foo : decltype(_test_has_foo::test<T>(0))
{};

Creo que la idea es usar SFINAE cuando se comprueba la existencia de una función miembro, por lo que en caso de que p->foo() no sea válida, solo se define la versión elipses de test, que devuelve el std::false_type. De lo contrario el el primer método se define para T* y devolverá std::true_type. El "switch" real ocurre en la segunda clase, que hereda del tipo devuelto por test. Esto parece inteligente y" ligero " en comparación con diferentes enfoques con is_same y cosas por el estilo.

El decltype con dos argumentos primero me pareció sorprendente, ya que pensé que solo obtiene el tipo de expresión. Cuando vi el código anterior, pensé que era algo así como " intenta compilar las expresiones y siempre devuelve el tipo del segundo. Fail if the expressions fail to compile" (so hide this specialization; SFINAE).

Pero:

Entonces pensé que podría usar este método para escribir cualquier comprobador "is valid expression", siempre y cuando dependa de algún tipo T. Ejemplo:

...
    template<class T>
    static auto test(T* p) -> decltype(bar(*p), std::true_type());
...

Http://ideone.com/dJkLPF

Esto, por lo que pensé, devolverá un std::true_type si y solo si bar se define aceptando un T como el primer parámetro (o si T es convertible, etc...), es decir: si bar(*p) se compilaría si se escribiera en algún contexto donde p se defina de tipo T*.

Sin embargo, la modificación anterior evalúa siempre a std::false_type. ¿Por qué es esto? No quiero arreglarlo con un código diferente complicado. Sólo quiero saber por qué no funciona como esperaba. Claramente, decltype con dos argumentos funciona diferente de lo que pensaba. No pude encontrar ninguna documentación; solo se explica con una expresión en todas partes.

Author: ildjarn, 2013-04-16

2 answers

Es una lista de expresiones separadas por comas, el tipo es idéntico al tipo de la última expresión de la lista. Generalmente se usa para verificar que la primera expresión es válida (compilable, think SFINAE), la segunda se usa para especificar que decltype debe regresar en caso de que la primera expresión sea válida.

 29
Author: Daniel Frey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-16 18:36:40

decltype no se necesitan dos argumentos. Simplemente, puede tener una expresión como argumento, y el operador coma es una forma de crear expresiones. Según el párrafo 5.18 / 1:

[...] Un par de expresiones separadas por una coma se evalúa de izquierda a derecha; la expresión izquierda es un valor descartado expresión (Cláusula 5). Cada cálculo de valor y efecto secundario asociado con la expresión izquierda es secuenciado antes de cada cálculo de valor y efecto secundario asociado con el expresión correcta. El tipo y el valor del resultado son el tipo y el valor del operando derecho ; el resultado es de la misma categoría de valor como su operando derecho, y es un campo de bits si su operando derecho es un glvalue y un campo de bits. Si el valor del derecho operando es un temporal (12.2), el resultado es que temporal.

Por lo tanto:

static_assert(std::is_same<decltype(42, 3.14), double>::value, "Will not fire");
 13
Author: Andy Prowl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-16 18:36:58