¿Se pueden templar las funciones lambda?


En C++11, ¿hay alguna forma de templar una función lambda? ¿O es inherentemente demasiado específico para ser templada?

Entiendo que puedo definir una clase/funtor con plantilla clásica en su lugar, pero la pregunta es más como: ¿el lenguaje permite templar funciones lambda?

Author: Peter Mortensen, 2010-08-26

10 answers

ACTUALIZACIÓN 2018: C++20 vendrá con lambdas templadas y conceptualizadas. La característica ya se ha integrado en el borrador estándar.


ACTUALIZACIÓN 2014: C++14 se ha lanzado este año y ahora proporciona lambdas polimórficas con la misma sintaxis que en este ejemplo. Algunos compiladores importantes ya lo implementan.


En It stands (en C++11), tristemente no. Lambdas polimórfico sería excelente en términos de flexibilidad y potencia.

La razón original por la que terminó siendo monomorfo debido a conceptos. Los conceptos dificultaron esta situación de código:

template <Constraint T>
void foo(T x)
{
    auto bar = [](auto x){}; // imaginary syntax
}

En una plantilla restringida solo puede llamar a otras plantillas restringidas. (De lo contrario, no se podrían verificar las restricciones.) Can foo invoke bar(x)? ¿Qué restricciones tiene la lambda (el parámetro para ella es solo una plantilla, después de todo)?

Los conceptos no estaban listos para abordar este tipo de cosas; requeriría más cosas como late_check (donde el concepto no se verificó hasta invocado) y esas cosas. Más simple era simplemente dejarlo todo y apegarse a lambdas monomórficas.

Sin embargo, con la eliminación de conceptos de C++0x, las lambdas polimórficas se convierten de nuevo en una proposición simple. Sin embargo, no puedo encontrar ninguna propuesta para ello. :(

 131
Author: GManNickG,
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
2018-04-25 10:21:18

Las lambdas de C++11 no se pueden templar como se indica en otras respuestas, pero decltype() parece ayudar cuando se usa una lambda dentro de una clase o función templada.

#include <iostream>
#include <string>

using namespace std;

template<typename T>
void boring_template_fn(T t){
    auto identity = [](decltype(t) t){ return t;};
    std::cout << identity(t) << std::endl;
}

int main(int argc, char *argv[]) {
    std::string s("My string");
    boring_template_fn(s);
    boring_template_fn(1024);
    boring_template_fn(true);
}

Impresiones:

My string
1024
1

He encontrado que esta técnica es útil cuando se trabaja con código templado, pero me doy cuenta de que todavía significa que los lambdas mismos no pueden ser templados.

 29
Author: Joel,
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-08-08 19:59:00

En C++11, las funciones lambda no se pueden templar, pero en la próxima versión del estándar ISO C++ (a menudo llamado C++14), esta característica se introducirá. [Fuente]

Ejemplo de uso:

auto get_container_size = [] (auto container) { return container.size(); };

Tenga en cuenta que aunque la sintaxis utiliza la palabra clave auto, la deducción de tipo no utilizará las reglas de la deducción de tipo auto, sino que utilizará las reglas de la deducción de argumento de plantilla. Ver también la propuesta para expresiones lambda genéricas (y la actualización para este).

 19
Author: Timo Türschmann,
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-11-18 11:18:49

Soy consciente de que esta pregunta es sobre C++11. Sin embargo, para aquellos que buscaron en Google y llegaron a esta página, las lambdas templadas ahora son compatibles con C++14 y se denominan Lambdas Genéricas.

[info] La mayoría de los compiladores populares soportan esta característica ahora. Microsoft Visual Studio 2015 es compatible. Soportes Clang. GCC soporta.

 8
Author: Ram,
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
2014-12-30 20:05:38

Me pregunto qué pasa con esto:

template <class something>
inline std::function<void()> templateLamda() {
  return [](){ std::cout << something.memberfunc() };
}

Usé código similar como este, para generar una plantilla y preguntarme si el compilador optimizará la función "wrapping".

 6
Author: ted,
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
2011-12-19 17:18:35

Echa un vistazo a Boost.Phoenix para lambdas polimórficas: http://www.boost.org/doc/libs/1_44_0/libs/spirit/phoenix/doc/html/index.html No requiere C++0x, por cierto :)

 3
Author: usta,
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
2010-09-05 09:03:22

Hay una extensión gcc que permite plantillas lambda :

// create the widgets and set the label
base::for_each(_widgets, [] <typename Key_T, typename Widget_T>
                         (boost::fusion::pair<Key_T, Widget_T*>& pair) -> void {
                             pair.second = new Widget_T();
                             pair.second->set_label_str(Key_T::label);
                          }
              );

Donde _widgets es un std::tuple< fusion::pair<Key_T, Widget_T>... >

 2
Author: user6559931,
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
2016-07-07 09:36:18

No estoy seguro de por qué nadie más ha sugerido esto, pero puede escribir una función templada que devuelva las funciones lambda. Lo siguiente resolvió mi problema, la razón por la que llegué a esta página:

template <typename DATUM>
std::function<double(DATUM)> makeUnweighted() {
  return [](DATUM datum){return 1.0;};
}

Ahora, cada vez que quiero una función que toma un tipo dado de argumento (por ejemplo, std::string), solo digo

auto f = makeUnweighted<std::string>()

Y ahora f("any string") devuelve 1.0.

Ese es un ejemplo de lo que quiero decir con "función lambda templada."(Este caso particular se utiliza para proporcionar automáticamente una ponderación inerte función cuando alguien no quiere ponderar sus datos, cualesquiera que sean sus datos.)

 1
Author: Jim Pivarski,
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
2016-04-27 08:45:01

He estado jugando con el último clang version 5.0.1 compilando con la bandera -std=c++17 y ahora hay un buen soporte para los parámetros de tipo automático para lambdas:

#include <iostream>
#include <vector>
#include <stdexcept>

int main() {
    auto slice = [](auto input, int beg, int end) {
        using T = decltype(input);
        const auto size = input.size();
        if (beg > size || end > size || beg < 0 || end < 0) {
            throw std::out_of_range("beg/end must be between [0, input.size())");
        }
        if (beg > end) {
            throw std::invalid_argument("beg must be less than end");
        }
        return T(input.begin() + beg, input.begin() + end);
    };
    auto v = std::vector<int> { 1,2,3,4,5 };
    for (auto e : slice(v, 1, 4)) {
        std::cout << e << " ";
    }
    std::cout << std::endl;
}
 1
Author: Doug Coburn,
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
2018-02-21 05:09:58

Aquí hay una solución que implica envolver la lamba en una estructura:

template <typename T>                                                   
struct LamT                                                             
{                                                                       
   static void Go()                                                     
   {                                                                    
      auto lam = []()                                                   
      {                                                                 
         T var;                                                         
         std::cout << "lam, type = " << typeid(var).name() << std::endl;
      };                                                                

      lam();                                                            
   }                                                                    
};   

Para usar do:

LamT<int>::Go();  
LamT<char>::Go(); 
#This prints 
lam, type = i
lam, type = c

El problema principal con esto (además de la escritura adicional) no puede incrustar esta definición de estructura dentro de otro método o se obtiene (gcc 4.9)

error: a template declaration cannot appear at block scope

También intenté hacer esto:

template <typename T> using LamdaT = decltype(                          
   [](void)                                                          
   {                                                                 
       std::cout << "LambT type = " << typeid(T).name() << std::endl;  
   });

Con la esperanza de que pudiera usarlo así:

LamdaT<int>();      
LamdaT<char>();

Pero obtengo el error del compilador:

error: lambda-expression in unevaluated context

Así que esto no funciona ... pero incluso si lo hizo compilar sería de carácter limitado utilizar porque todavía tendríamos que poner el "usando LamdaT" en el ámbito del archivo (debido a que es una plantilla) que tipo de derrota el propósito de lambdas.

 0
Author: rmccabe3701,
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
2015-08-05 14:41:02