Вызов std :: make_tuple с лямбдами в шаблоне с переменными значениями — это должно работать в C ++ 11?

в C ++ 11 лямбда-функция — это объект, и с ним должна быть возможность вызывать make_tuple, верно?

void foobar() {
auto t = std::make_tuple([](){ std::make_shared<int>(); });
}

Этот код работает для меня.

Теперь, что произойдет, если мы добавим шаблон с переменными параметрами:

#include <tuple>
#include <memory>

template <class... T>
void foobar() {
auto t = std::make_tuple([](){ std::make_shared<T>(); }...);
}

int main(int, char**)
{
foobar<int, float, double>();
return 0;
}

Этот не компилируется в GCC 4.7.2

main.cpp: In lambda function:
main.cpp:6:54: error: parameter packs not expanded with '...':
main.cpp:6:54: note:         'T'
main.cpp: In function 'void foobar()':
main.cpp:6:57: error: expansion pattern '#'lambda_expr' not supported by dump_expr#<expression error>' contains no argument packs
main.cpp: In instantiation of 'void foobar() [with T = {int, float, double}]':
main.cpp:11:29:   required from here

Интересно, является ли этот код верным стандартом?

3

Решение

Это известная ошибка в gcc: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41933 (первоначальный пример — это другой шаблон, охватывающий захват пакетов параметров, но проблема, лежащая в основе этого и слитых ошибок, заключается в том, что gcc просто не реализовал пересечение лямбда-выражений и переменных).

Что касается стандарта, то это совершенно приемлемый код.

6

Другие решения

Подход № 1:

Кажется, простой способ обойти это std::function:

#include <tuple>
#include <memory>

template <class T>
std::function<std::shared_ptr<T>()> make_shared_lambda() {
return [](){ return std::make_shared<T>(); };
}

template <class... T>
void foobar() {
auto factories = std::make_tuple(make_shared_lambda<T>()...);
auto tracer = std::get<2>(factories)();
}

// demonstration
#include <cstdio>
struct Tracer {
Tracer() { puts("Tracer()");   }
~Tracer() { puts("~Tracer()");  }
};

int main()
{
foobar<int, float, Tracer>();
}

Печать

Tracer()
~Tracer()

Подход № 2:

Очевидно, что в производительности std::functionТип стирания. Вы можете легко использовать тот факт, что лямбды без сохранения состояния можно преобразовать в указатели функций (стандарт 5.1.2 / 6):

#include <tuple>
#include <memory>

template <class T> auto make_shared_f() -> std::shared_ptr<T>(*)()
{
return []() { return std::make_shared<T>(); };
}

template <class... T> std::tuple<std::shared_ptr<T>(*)()...> foobar() {
return std::make_tuple(make_shared_f<T>()...);
}

// demonstration
int main()
{
auto factories = foobar<int, float, double>();
auto double_ptr = std::get<2>(factories)();
}

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

template <typename T> using shared_factory = std::shared_ptr<T>(*)();

template <class T> shared_factory<T> make_shared_f() {
return []() { return std::make_shared<T>(); };
}
4

По вопросам рекламы [email protected]