【问题标题】:lambda function uses its parameter as template parameter calling template functionlambda 函数使用其参数作为模板参数调用模板函数
【发布时间】:2020-05-14 11:51:23
【问题描述】:

以下是示例代码,无法编译。

我们使用 iteration 函数来迭代某个范围并运行 lambda 回调函数。 iterate 函数会将一些指示(即 type)传递给回调 lambda 函数,然后它会根据指示进行工作。由于这些指示在编译时是固定的,我相信有一种方法可以在运行时消除所有指示开销。但是如何..?

template<typename FuncT>
void iterate(const FuncT& func) {
    for(int i = 0; i < 5; ++i)
        func(0, i);
    for(int i = 0; i < 5; ++i)
        func(1, i);
}

template<int d> int getValue(int i) { return d+i; }
// this has run-time overhead compared to the template version
// int getValue(int d, int i) {return d+i; }

int main() {
    iterate([&](const int type, int index){
        // error: cannot compiler here
        // candidate template ignored: invalid explicitly-specified argument for template parameter 'd'
        std::cout<<getValue<type>(index)<<std::endl;
    });
}

【问题讨论】:

  • getValue&lt;type&gt;(index) 中,类型的值必须在编译时知道,但直到在运行时调用 lambda 时才知道。你到底想达到什么目标?
  • @WernerHenze 你是对的。它只是一个示例代码。在我的项目中,传递给 lambda 函数的参数(即类型)在编译时是已知的。我只是想知道有没有办法通过模板将它从运行时中删除。我猜 Evg 提供了一个非常酷的解决方案。

标签: c++ templates metaprogramming


【解决方案1】:

您不能将运行时变量用作模板参数,它应该是编译时常量。但是您可以将常量包装到 std::integral_constant 中,以将常量值编码为类型:

template<typename Func>
void iterate(Func func) {
    for(int i = 0; i < 5; ++i)
        func(std::integral_constant<int, 0>{}, i);
    for(int i = 0; i < 5; ++i)
        func(std::integral_constant<int, 1>{}, i);
}

template<int d>
int getValue(int i) {
    return d + i;
}

int main() {
    iterate([&](auto type, int index) {
        std::cout << getValue<type>(index) << std::endl;
    });
}

std::integral_constant 可以隐式转换为基础类型的值。在getValue&lt;type&gt;(index)中,type被转换为int类型的包装值。

Demo

【讨论】: