lambda 可以实例化模板函数吗?
Can a lambda instantiate a template function?
关于使用 C++14 通用 lambda 或 C++20 模板 lambda 的问题通常是关于生成具有适当参数化类型的 lambda。
我的问题是,lambda 参数或其求值是否可能强制实例化(或专业化)模板,例如模板函数?参数 (n)
需要限定为 constexpr
才能工作。
template <int n> ret_type fn (...) {...}
...
auto fx = [] (int n) { return fn<n>(...) }
我并不完全了解 C++20 或更新的工作提案,并且承认在 C++17 lambda 和其他边缘功能中 constexpr
等仍然存在细微差别,这让我经常查找 cppreference
、Josuttis 和其他人。
我知道这接近 XY 问题。由于模板实例化是在编译时执行的,因此模板参数的 lambda 表达式似乎是一种反模式。但是,如果类型和常量值在编译时已知,模板 可以 被实例化,是否有任何建议允许这种机制?
所问问题的答案是:是的,lambda 的主体可以实例化模板。
你问题中的具体例子是不可能的,因为函数参数不能是constexpr
,这是用作模板参数所必需的。
您可以使用可从 lambda 定义的范围访问的 constexpr 变量:
template<int N>
void something();
constexpr int N = 10;
int main()
{
auto f = [] { something<N>(); };
f();
}
实例 here,其中 something
在 de lambda 表达式的主体内实例化。但我不认为那是你所追求的。请注意,调用 lambda 对象不会(而且永远不会导致)模板的实例化。
你的问题的答案在技术上是是的,lambda 体可以实例化模板函数。实际示例不起作用,因为不能以这种方式使用 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 转换。
我们可以将其传递给 lambda,只要 lambda 按值获取它,我们就可以将其转换为 lambda 中的 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") );
做正确的事tm.
关于使用 C++14 通用 lambda 或 C++20 模板 lambda 的问题通常是关于生成具有适当参数化类型的 lambda。
我的问题是,lambda 参数或其求值是否可能强制实例化(或专业化)模板,例如模板函数?参数 (n)
需要限定为 constexpr
才能工作。
template <int n> ret_type fn (...) {...}
...
auto fx = [] (int n) { return fn<n>(...) }
我并不完全了解 C++20 或更新的工作提案,并且承认在 C++17 lambda 和其他边缘功能中 constexpr
等仍然存在细微差别,这让我经常查找 cppreference
、Josuttis 和其他人。
我知道这接近 XY 问题。由于模板实例化是在编译时执行的,因此模板参数的 lambda 表达式似乎是一种反模式。但是,如果类型和常量值在编译时已知,模板 可以 被实例化,是否有任何建议允许这种机制?
所问问题的答案是:是的,lambda 的主体可以实例化模板。
你问题中的具体例子是不可能的,因为函数参数不能是constexpr
,这是用作模板参数所必需的。
您可以使用可从 lambda 定义的范围访问的 constexpr 变量:
template<int N>
void something();
constexpr int N = 10;
int main()
{
auto f = [] { something<N>(); };
f();
}
实例 here,其中 something
在 de lambda 表达式的主体内实例化。但我不认为那是你所追求的。请注意,调用 lambda 对象不会(而且永远不会导致)模板的实例化。
你的问题的答案在技术上是是的,lambda 体可以实例化模板函数。实际示例不起作用,因为不能以这种方式使用 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 转换。
我们可以将其传递给 lambda,只要 lambda 按值获取它,我们就可以将其转换为 lambda 中的 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") );
做正确的事tm.