【问题标题】:How to avoid lambda functions with a known function parameter?如何避免具有已知函数参数的 lambda 函数?
【发布时间】:2017-07-19 05:49:55
【问题描述】:

在下面的代码中,我有一个名为data 的变量。它在自身内部包含一个函数,以便稍后调用它们。假设data 是在另一个库中定义的,我无法更改它的类型。我为它的每个成员分配了一个模板函数,其中该函数的一部分是已知的 (s3),并且在调用它时必须给出一部分 (true)。我不能通过这样的事情:

data[0]=test_func(?,s3);  // error

相反,我必须将 lambda 函数传递给它:

data[0]=[](bool b){test_func(b,s3);}; // ok

但是 lambda 函数看起来并不整洁,尤其是当我们有一个包含 100 个这些赋值的数组时。有什么方法可以通过以任何方式更改 test_func 来避免 lambda 函数吗?即使在 test_func 中使用 lambda 对我来说也是可以的,因为它只写了一次。

#include <iostream>
#include <functional>

template<typename F>
void test_func(bool b,F f)
{
    if(b)
        f();
}

void s1()
{
    std::cout<<"s1 \n";
}

void s2()
{
    std::cout<<"s2 \n";
}

void s3()
{
    std::cout<<"s3 \n";
}

int main()
{
    test_func(true,s1);
    test_func(true,s2);
    test_func(false,s1);
    test_func(true,s2);
    /////////////////
    std::function<void(bool)> data[100];
    // data=test_func(?,s3);  // error
    data[0]=[](bool b){test_func(b,s3);}; // ok
    data[0](true);
    return 0;
}

【问题讨论】:

  • 不就是std::function&lt;void (bool)&gt; foo(F f) { return [](bool b) { test_func(b, f); }; }吗?
  • 就目前而言,最好的解决方案是简单地使用 lambda 函数。 std::bind 试图这样做,但使用它需要学习它的迷你语言(对于任何阅读代码的人),并且往往会使编译器更难优化。此外,它最终只比 lambda 函数短。
  • @melpomene,您如何将其放入此代码中?
  • @Justin,函数可以返回 lambda 吗?喜欢combine(test_func,s3)
  • @ar2015 data[0] = foo(s3);

标签: c++ c++11 templates lambda std-function


【解决方案1】:

如果您想完全避免使用lambda 函数以及templates,您可以使用函数式(带有operator() 的类):

typedef void (&F)(void);
class TestFunc {
    F f;
    public:
    TestFunc(const F f) : f(f) {}
    void operator()(bool B) const { 
        if(B) f(); 
    }
};

TestFunc(s3) 分配它。只需typedefF到函数类型,不需要模板:

typedef void (&F)(void);

并完全删除模板 - 如果可能的话,我通常更喜欢更少的模板,但这就是品味。仅当您需要不同的函数签名支持时才会真正调用模板。

要使用标准库函数,只需更改 typedef:

typedef std::function<void(void)> F;

【讨论】:

  • template&lt;typename F&gt;? error: ISO C++ forbids declaration of ‘Functional’ with no type
  • 非常感谢。这个解决方案也可以扩展到std::function吗?
【解决方案2】:

如果每个s_n 都是具有相同签名的常规函数​​,您可以从test_func 中删除该f 参数,并将函数本身作为模板参数传递。

template<void(&f)()>
void test_func(bool b)
{
    if(b)
        f();
}

并像这样使用:

data[0] = test_func<s1>;

[temp.param/4] 明确允许函数指针和引用作为模板非类型参数:

非类型模板参数应具有以下之一 (可选 cv 限定)类型:

[...]

  • 指向对象的指针或指向函数的指针,
  • 对对象的左值引用或对函数的左值引用,

【讨论】:

  • 再见兄弟。也可以通过 std::function 而不是指针来完成吗?
  • @ar2015 - 不,因为对于初学者来说,std::function 不能是常量表达式。它具有允许类型擦除的状态。仅允许函数指针是因为它在某种意义上也在编译时“固定”了。
  • 是否意味着指针在优化方面优于std::function
  • @ar2015 - 不能做出如此笼统的陈述。 std::function 的存在是为了解决特定问题。当然,这并非没有开销,但是没有办法使用常规函数来做到这一点。我能看到的唯一明显改进是,如果一个函数是可内联的,编译器将从模板参数的函数引用中看到它,就像你直接在模板主体中编写它一样。
  • @ar2015 - 但你应该首先关注正确性。过早的优化(以及对它的关注)是许多软件问题的根源。
【解决方案3】:

您可以在辅助函数中创建您的 lambda:

#include <iostream>
#include <string>
#include <functional>
#include <vector>

template<typename F>
void test_func(bool b,F f) {
    if(b) {
       f();
    }
}

std::function<void(bool)> wrap_function(const std::function<void(void)> &f) {
    return [f](bool b){test_func(b,f);};
}

void s1() {
    std::cout<<"s1 \n";
}

int main() {
    std::vector<std::function<void(bool)>> data;

    data.push_back(wrap_function(s1));

    data[0](true);
}

您应该使用std::vectorstd::array 或其他标准容器,而不是std::function&lt;void(bool)&gt; data[100]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-07
    • 1970-01-01
    • 2022-06-15
    • 1970-01-01
    相关资源
    最近更新 更多