Могут ли лямбда-функции быть шаблонными?



В C++11, есть ли способ шаблона лямбда-функции? Или это по своей сути слишком специфично, чтобы быть шаблонизированным?



Я понимаю, что вместо этого я могу определить классический шаблонный класс/функтор, но вопрос больше похож: позволяет ли язык шаблонизировать лямбда-функции?

832   10  

10 ответов:

обновление 2018: C++20 будет поставляться с шаблонными и концептуализированными лямбдами. Функция уже интегрирована в стандартный проект.


обновление 2014: C++14 были выпущены в этом году и теперь предоставляют полиморфные лямбды с тем же синтаксисом, что и в этом примере. Некоторые крупные компиляторы уже реализуют его.


в нем стоит (в C++11), к сожалению, нет. Полиморфные лямбды были бы превосходны с точки зрения гибкости и сила.

первоначальная причина, по которой они оказались мономорфными, была связана с понятиями. Концепции усложнили эту ситуацию с кодом:

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

в ограниченном шаблоне можно вызывать только другие ограниченные шаблоны. (В противном случае ограничения не могут быть проверены.) Может foo invoke bar(x)? Какие ограничения имеет лямбда (параметр для него-это просто шаблон, в конце концов)?

концепции не были готовы решать такие вещи; это было бы требуется больше вещей, как late_check (где концепция не была проверена до вызова) и прочее. Проще было просто отбросить все это и придерживаться мономорфных лямбд.

однако с удалением понятий из C++0x полиморфные лямбды снова становятся простым предложением. Однако я не могу найти никаких предложений для этого. : (

C++11 лямбды не могут быть шаблонизированы, как указано в других ответах, но decltype() Кажется, помогает при использовании лямбда в шаблонном классе или функции.

#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);
}

принты:

My string
1024
1

я обнаружил, что этот метод помогает при работе с шаблонным кодом, но понимаю, что это все еще означает, что сами лямбды не могут быть шаблонными.

В C++11 лямбда-функции не могут быть шаблонизированы, но в следующей версии стандарта ISO C++ (часто называемого C++14) эта функция будет введена. [источник]

пример использования:

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

обратите внимание, что хотя синтаксис использует ключевое слово auto, тип вычета не будет использовать правила auto введите вычет, но вместо этого используйте правила вычета аргумента шаблона. Также смотрите предложение для общего лямбда выраженияобновление к этому).

Я знаю, что этот вопрос касается C++11. Однако для тех, кто погуглил и приземлился на этой странице, шаблонные лямбды теперь поддерживаются в C++14 и идут под именем Generic Lambdas.

[info] большинство популярных компиляторов теперь поддерживают эту функцию. Microsoft Visual Studio 2015 поддерживает. Лязг поддерживает. GCC поддерживает.

интересно, что это:

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

я использовал подобный код, чтобы создать шаблон и задаться вопросом, будет ли компилятор оптимизировать функцию "обертывания".

взгляните на Boost.Феникс для полиморфных лямбд: http://www.boost.org/doc/libs/1_44_0/libs/spirit/phoenix/doc/html/index.html Не требует C++0x, кстати:)

есть расширение gcc позволяет лямда-шаблоны:

// 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);
                          }
              );

здесь _widgets это std::tuple< fusion::pair<Key_T, Widget_T>... >

Я не уверен, почему никто другой не предложил это, но вы можете написать шаблонную функцию, которая возвращает лямбда-функции. Следующее решило мою проблему, причина, по которой я пришел на эту страницу:

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

теперь всякий раз, когда я хочу функцию, которая принимает данный тип аргумента (например,std::string), Я просто говорю

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

и теперь f("any string") возвращает 1.0.

это пример того, что я имею в виду под "шаблонной лямбда-функцией.(Этот конкретный случай используется для автоматически обеспечивает инертную функцию взвешивания, когда кто-то не хочет взвешивать свои данные, какими бы ни были их данные.)

я играл с последним clang version 5.0.1 компиляция с -std=c++17 флаг и теперь есть хорошая поддержка параметров автоматического типа для лямбд:

#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;
}

вот одно решение, которое включает в себя обертывание Ламбы в структуру:

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

      lam();                                                            
   }                                                                    
};   

для использования do:

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

основная проблема с этим (помимо дополнительного ввода) вы не можете встроить это определение структуры в другой метод или вы получаете (gcc 4.9)

error: a template declaration cannot appear at block scope

Я тоже пытался сделать это:

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

С надеждой, что я мог бы использовать его как это:

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

но я получаю ошибку компилятора:

error: lambda-expression in unevaluated context

так это не работает ... но даже если бы он компилировался, он был бы ограничен используйте, потому что нам все равно придется поставить "using LamdaT" в области файлов (потому что это шаблон), который как бы поражает цель лямбд.

Comments

    Ничего не найдено.