tutorial smart remix español curso aprender c++ gcc c++11 tuples

c++ - smart - Devolver una tupla desde una función utilizando una sintaxis de inicialización uniforme



solidity español (2)

A diferencia del pair<> , la construcción implícita de una tuple<> desafortunadamente no es posible. Tienes que usar make_tuple() :

#include <tuple> std::tuple<double,double> dummy() { return std::make_tuple(2.0, 3.0); // OK } int main() { std::tuple<double,double> a = dummy(); return 0; }

std::tuple tiene un constructor variadic, pero está marcado como explicit . Por lo tanto, no se puede utilizar en esta situación, donde un temporal debe ser implícitamente construible. Según el párrafo 20.4.2 de la norma C ++ 11:

namespace std { template <class... Types> class tuple { public: [...] explicit tuple(const Types&...); // Marked as explicit! template <class... UTypes> explicit tuple(UTypes&&...); // Marked as explicit!

Por el mismo motivo, es ilegal usar la sintaxis de inicialización de copia para inicializar tuplas:

std::tuple<double, double> a = {1.0, 2.0}; // ERROR! std::tuple<double, double> a{1.0, 2.0}; // OK

O para construir una tupla implícitamente al pasarla como un argumento a una función:

void f(std::tuple<double, double> t) { ... } ... f({1.0, 2.0}); // ERROR! f(make_tuple(1.0, 2.0)); // OK

En consecuencia, si construye su std::tuple explícitamente cuando lo devuelve en dummy() , no se producirá ningún error de compilación:

#include <tuple> std::tuple<double,double> dummy() { return std::tuple<double, double>{2.0, 3.0}; // OK } int main() { std::tuple<double,double> a = dummy(); return 0; }

El siguiente código se compila con clang (libc ++) y falla con gcc (libstdc ++). ¿Por qué gcc (libstdc ++) se queja sobre una lista de inicializadores? Pensé que el argumento de retorno estaba usando una sintaxis de inicialización uniforme.

std::tuple<double,double> dummy() { return {2.0, 3.0}; } int main() { std::tuple<double,double> a = dummy(); return 0; }

Error: línea 22: la conversión a ''std :: tuple'' desde el inicializador / list usaría el constructor explícito ''constexpr std :: tuple <_T1, _T2> :: tuple (_U1 & / &, _U2 &&) [with _U1 = double; _U2 = doble; = vacío; _T / 1 = doble; _T2 = doble] ''

Nota: GCC (libstdc ++) (y clang (libc ++)) aceptan

std::tuple<double,double> dummy {1.0, 2.0};

¿No es el mismo caso?

Actualización: esta es una extensión de libc ++, consulte http://llvm.org/bugs/show_bug.cgi?id=15299 y también la respuesta de Howard Hinnant a continuación.


La respuesta que da Andy Prowl es correcta. Quería comentar sobre la implementación de libc ++, y el formato de comentarios no me permite espacio suficiente o opciones de formato.

Daniel Krügler y yo tuvimos una conversación hace aproximadamente un año sobre este tema, y ​​él me convenció de que este tema era digno de poner una extensión en libc ++ para obtener experiencia de campo. Y hasta ahora el feedback ha sido positivo. Sin embargo, quiero aclarar: esto no es tan simple como eliminar explicit de la explicit constexpr tuple(UTypes&&...) ctor explicit constexpr tuple(UTypes&&...) .

El plan de Daniel es darle a la tuple un constructor que respete perfectamente la construcción implícita / explícita de cada elemento. Y si cada elemento se construye implícitamente a partir de cada argumento en la lista de inicializadores, entonces la construcción de la tupla es implícita, de lo contrario será explícita.

Por ejemplo:

Dado:

#include <tuple> struct A { }; struct B { B() = default; B(A); }; struct C { C() = default; explicit C(A); };

Entonces:

std::tuple<> test0() { return {}; // ok }

No hay mucho que decir sobre eso. Pero también esto está bien:

std::tuple<B> test1B() { return {A()}; // ok B(A) implicit }

Porque la conversión de A a B es implícita. Sin embargo, el siguiente es un error de tiempo de compilación:

std::tuple<C> test1C() { return {A()}; // error, C(A) is explicit }

Porque la conversión de A a C es explícita. Esta lógica continúa para tuplas de elementos múltiples. Para que ocurra una conversión implícita, cada elemento debe tener una conversión implícita de la lista de argumentos:

std::tuple<A, B> test2B() { return {A(), A()}; // ok each element has implicit ctor } std::tuple<A, C> test2C() { return {A(), A()}; // error, C(A) is explicit }

Debo enfatizar: Esta es una extensión libc ++ en este momento.

Actualizar

Chico hizo una buena sugerencia de que actualice esta respuesta:

Desde que se dio esta respuesta, Daniel Krügler escribió un paper y lo presentó al comité de C ++ en Bristol el pasado abril. Aunque el documento fue bien recibido, fue revisado demasiado tarde en la semana para votar en el borrador de trabajo actual.

Actualizar

La propuesta de Daniel es ahora parte del borrador de trabajo actual . La implementación de libc ++ ahora está configurada para convertirse en estándar en este aspecto para el próximo estándar de C ++ (esperamos que C ++ 17).