#c #lambda #c 17 #template-specialization #c -experimental
Вопрос:
Вопросы, касающиеся использования универсальных лямбд C 14 или шаблонных лямбд C 20, обычно касаются создания лямбд с соответствующими параметризованными типами.
Мой вопрос в том, возможно ли для параметра lambda или его оценки принудительно создать экземпляр (или специализацию) шаблона, например, функции шаблона? Параметр (n)
должен быть квалифицирован так constexpr
, чтобы это работало.
template <int n> ret_type fn (...) {...}
...
auto fx = [] (int n) { return fn<n>(...) }
Я не полностью в курсе C 20 или новых рабочих предложений и признаю, что все еще есть нюансы с constexpr
и т. Д. В лямбда-выражениях C 17 и других функциях edge, которые заставляют меня cppreference
довольно часто искать , Josuttis и других.
Я знаю, что это близко к XY-проблеме. Поскольку создание экземпляра шаблона выполняется во время компиляции, лямбда-выражение для параметра шаблона кажется анти-шаблоном. Но поскольку шаблоны могут быть созданы, если типы и постоянные значения известны во время компиляции, есть ли какие-либо предложения, позволяющие такой механизм?
Комментарии:
1. параметры функции не могут быть
constexpr
такими, чтобы ваш конкретный пример не работал. Но я полагаю, что это помимо вопроса, который вы задаете?2. @rubenvb — да. AFAIK, там нет
concept
/requires
синтаксиса, подобного некоторым(constexpr int n)
— я не вижу стандартного решения, но мне любопытны языковые предложения и тому подобное. Например, лямбды получают больше возможностей с каждым стандартом с момента их введения.3. @BrettHale ты имеешь в виду, например
consteval
?4. @Mgetz — В некотором смысле. Если параметр специализации шаблона является
consteval
выражением. Мой вопрос начинает казаться все более и более непрактичным, когда я думаю об этом, учитывая ограничения, которые потребовались бы для такой гипотетической «лямбды»…5. @BrettHale Я думаю, что вы, вероятно, задаете неправильный вопрос. Я бы посоветовал спросить о том, что вы пытаетесь сделать, а не о потенциальном решении. Здесь есть возможности (я делал сумасшедшие вещи
std::integer_sequence
), но, не зная, что вы пытаетесь сделать, трудно дать хороший ответ.
Ответ №1:
Ответ на ваш вопрос технически да, лямбда-тела могут создавать экземпляры функций шаблона. Фактический пример не работает, потому int n
что в качестве параметра его нельзя использовать таким образом.
Существует простой обходной путь
template<auto x>
using constant_t = std::integral_constant< std::decay_t<decltype(x)>, x >;
template<auto x>
constexpr constant_t<x> constant = {};
template <int n> int fn () { int arr[n] = {0}; return sizeof(arr); }
auto fx = [] (auto n) { return fn<n>(); };
std::cout << fx( constant<3> );
Здесь я создал шаблон constant<x>
переменной, который создает экземпляр std::integral_constant<X, x>
. Это тип без состояния (но не бесполезный!), который имеет преобразование constexpr в его значение.
Мы можем передать это в лямбду, и до тех пор, пока лямбда принимает его по значению, мы можем затем преобразовать его в constexpr
значение внутри лямбды, включая передачу его в качестве параметра, не относящегося к типу шаблона, создание экземпляра специализации функции шаблона, как вы просите.
Это можно сделать без шаблона constant
переменной, т. е. если у вас нет auto
поддержки параметров:
template<std::size_t N>
using index_t = std::integral_constant<std::size_t, N>;
template<std::size_t N>
constexpr index_t<N> index = {};
мы можем использовать его версию для определенного типа и просто передать ее, и она работает точно так же.
В стороне, constant<?>
это весело. Например:
using upFILE=std::unique_ptr<
std::FILE,
constant_t<std::fclose>
>;
upFILE file( fopen("hello.txt", "r") );
поступает правильно, тм.
Комментарии:
1. Так вот как бы вы это сделали, не злоупотребляя
std::integer_sequence
хорошим…2. Это довольно элегантно. Спасибо.
Ответ №2:
Ответ на заданный вопрос таков: да, тело лямбды может создавать экземпляры шаблонов.
Конкретный пример в вашем вопросе невозможен, так как параметры функции не могут быть constexpr
, что необходимо для того, чтобы что-то использовалось в качестве параметра шаблона.
Вы можете использовать переменные constexpr, доступные из области определения лямбды:
template<int N>
void something();
constexpr int N = 10;
int main()
{
auto f = [] { something<N>(); };
f();
}
Здесь приведен живой пример, в котором something
экземпляр находится в теле выражения де лямбда. Но я не думаю, что это то, что вам нужно. Обратите внимание, что вызов лямбда-объекта не приводит (и никогда не мог привести) к созданию экземпляра шаблона.
Комментарии:
1. Спорный момент: вы можете сделать это, злоупотребляя пакетами параметров и
std::integer_sequence
. Не то чтобы я бы рекомендовал это делать.2. Значение, которое вы передадите шаблону, все равно будет чем-то (косвенно)
constexpr
и никогда не сможет исходить, например, из пользовательского ввода. Это, на мой взгляд, ничем не отличается от использования, например, T::value_type, где T используется в качестве типа параметра шаблона функции.3. не возражаю, но я не припомню, чтобы ОП говорил, что им нужна такая гибкость.