【问题标题】:Is it possible to explicitly specify template arguments in a generic lambda passed to a function?是否可以在传递给函数的通用 lambda 中显式指定模板参数?
【发布时间】:2021-11-24 10:34:09
【问题描述】:

我想在一个大小在编译时已知的小容器(如 4-8 个元素)上创建一个编译时循环。 创建一个简单的循环并不难:我可以创建一个模板仿函数F 重载operator() 并像下面的代码一样调用它

constexpr std::array<T, N> array{/*fill the array*/};

template <std::size_t index> struct F
{
    void operator()()
    {
        std::vector<T> some_container{/*fill it in runtime*/};
        some_container[index + some_offset] += std::get<index>(array); // Use safe array access
    }
};

template <template<std::size_t> typename F, std::size_t... I>
void iterator_implementation(
    const std::index_sequence<I...> /*unused*/)
{
    ((F<I>{}()), ...);
}

template <template<std::size_t> typename F>
void iterator()
{
    iterator_implementation<F>(std::make_index_sequence<array.size()>{});
}

但是,如果我想创建十个这样的循环并想方便地传递一堆引用(闭包),我绝对应该使用 lambda 函数。 为了在 lambda 中使用 std::get,我应该使用通用 lambda。 所以,下面例子中的函子可能会变成

auto f = [&some_container, some_offset]<std::size_t index>()
{
    some_container[index + some_offset] += std::get<index>(array); // Use safe array access
};

我不能简单地将这个 lambda 传递给 iterator,因为在不指定模板参数的情况下不可能传递模板类型的变量,而且我不能简单地获取 lambda 的类型并将其作为 F 提供为了调用 F&lt;I&gt;{} 重新创建 lambda。 如果我使用typename F而不是template&lt;std::size_t&gt; typename F,我不能调用f&lt;I&gt;,因为typename没有模板参数,所以不能和它们一起使用。

我也可以将std::get&lt;index&gt;(array) 和index 作为普通参数传递给lambda 函数,避免使用模板参数,但节省了访问的安全性。不过,我希望尽可能尝试使用编译时常量来检查它是如何工作的。 我相信将编译时常量数字作为模板参数传递可以帮助编译器优化我的代码,而不是数字是我的代码中的普通变量(即使智能编译器应该“看到”这个并优化调用)。 所以,这是一个关于新知识的问题,而不是讨论这种方法是否有帮助。

是否可以根据需要在参数包的折叠中使用通用 lambda?

P。 S。 尽管有问题标题,但它不是 How to pass generic lambda into function 的重复项,因为在我的问题模板参数中应该明确指定,而在该问题中可以推导出它。

【问题讨论】:

  • 它是 operator() 是一个模板,而不是 lambda。 godbolt.org/z/rYTP1KTYc ?
  • @JeffGarrett,非常感谢!我应该更仔细地阅读文档。他们从字面上说“通用 lambda,operator() 是一个带有两个参数的模板”。您能否将问题作为答案而不是评论来回答?我希望将其标记为最佳答案。

标签: c++ templates lambda c++20 non-type-template-parameter


【解决方案1】:

在通用 lambda 中,operator() 是模板,但 lambda 类型不是。

不需要在索引F&lt;I&gt;{}() 处实例化模板,而是需要在索引处实例化operator()。由于 lambda 具有捕获功能,因此需要将其而不只是类型作为模板参数传递。

替换:

template <template<std::size_t> typename F, std::size_t... I>
void iterator_implementation(
    const std::index_sequence<I...> /*unused*/)
{
    ((F<I>{}()), ...);
}

与:

template <typename F, std::size_t... I>
void iterator_implementation(F f,
    const std::index_sequence<I...> /*unused*/)
{

    ((f.template operator()<I>()), ...);
}

完整示例:https://godbolt.org/z/rYTP1KTYc

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-29
    • 2019-11-30
    • 2015-09-10
    • 2016-03-15
    • 1970-01-01
    • 2017-07-08
    • 1970-01-01
    相关资源
    最近更新 更多