简体   繁体   English

将函数作为模板参数传递给成员函数

[英]Passing function as template argument to a member function

I am trying to pass function as template argument to a function in a class, but there is some mistake. 我试图将函数作为模板参数传递给类中的函数,但是有一些错误。 The code is giving an error error: missing template arguments before 'obj' . 代码给出了错误error: missing template arguments before 'obj' How can I fix this so that it compiles? 我该如何修复它以便编译?

#include<iostream>
double sum_fun(const double &a, const double &b)
{ std::cout<<a+b<<"\n"; }

template <typename F>
class B 
{
    public:
    void fb()(F f1)
    {
        f1(10.1,10.2);
    }
};

int main()
{
    B obj(sum_fun); //error
    obj.fb(); //error
    return 0;
}

There is a misunderstanding of how classes work. 对课程的运作方式存在误解。

int main()
{
    B obj(sum_fun); // calls B constructor with parameter `sum_fun`
    obj.fb(); // calls member function B::fb() with no parameters
    return 0;
}

Both lines raise an error as 这两行都会引发错误

  1. Your class has no constructor which takes a single parameter. 您的类没有构造函数,它只接受一个参数。
  2. void fb()(F f1) is illegal syntax. void fb()(F f1)是非法语法。 To declare a member function, use only one set of parentheses: either void fb() or void fb(F f1) . 要声明成员函数,只使用一组括号: void fb()void fb(F f1) The latter is incorrect in our case, as your member function call obj.fb() passes no parameters. 后者在我们的例子中是不正确的,因为你的成员函数调用obj.fb()没有传递任何参数。

To fix this, write up a constructor, store the function as a member variable, and use that variable in the function fb() . 要解决这个问题,请编写一个构造函数,将该函数存储为成员变量,并在函数fb()使用该变量。

template <typename F>
class B 
{
public:
    // constructor, initialises member `m_func` through member initialisation
    B(F func) : m_func(func) {}

    void fb()
    {
        m_func(10.1,10.2);
    }

private:
    F m_func;

};

In C++17, thanks to automatic template deduction, no errors are now emitted. 在C ++ 17中,由于自动模板推导,现在不会发出任何错误。 But in lower standards (eg C++11), template deduction is lacking and thus, the full templated type needs to be specified when declaring obj . 但是在较低的标准(例如C ++ 11)中,缺少模板推导,因此,在声明obj时需要指定完整的模板类型。

So in standards below C++17, the main function should be: 所以在C ++ 17以下的标准中,主要功能应该是:

int main()
{
    // C++11: using a function pointer to denote type
    B<double(*)(const double&, const double&)> obj(sum_fun);

    // ok in C++17, looks cleaner too
    // B obj(sum_fun);

    obj.fb();
    return 0;
}

Here, double(*)(const double&, const double&) is a function pointer , ie a pointer to a function which returns a double and takes two parameters, both of type const double& . 这里, double(*)(const double&, const double&)是一个函数指针 ,即一个指向函数的指针 ,该函数返回一个double并且接受两个参数,类型为const double& Function pointers may be considered as a type, which satisfies the template ( template<typename F> ). 函数指针可以被视为一种类型,它满足模板( template<typename F> )。

Just like we do std::vector<int> and std::vector<double> , we can also do std::vector<double(*)(const double&, const double&)> to denote a vector of functions returning double and taking const double& as parameters. 就像我们执行std::vector<int>std::vector<double> ,我们也可以执行std::vector<double(*)(const double&, const double&)>来表示返回double的函数向量。将const double&作为参数。

And by the way, sum_fun also raises a warning: nothing is returned even though the return type is double ... better specify void as the return type instead. 顺便说一句, sum_fun也会引发一个警告:即使返回类型是double ,也不会返回任何内容...更好地指定void作为返回类型。

C++11 Demo C ++ 11演示
C++17 Demo C ++ 17演示


Is it possible to pass function as argument directly to B::fb() instead of creating constructor B::B(F) and storing in local variable? 是否可以将函数作为参数直接传递给B::fb()而不是创建构造函数B::B(F)并存储在局部变量中?

Certainly. 当然。

#include <iostream>

void sum_fun(const double& a, const double& b)
{
    std::cout << a+b << "\n";
}

template <typename F>
class B 
{
public:
    void fb(F func)
    {
        func(10.1,10.2);
    }
};

int main()
{
    B<void(*)(const double&, const double&)> obj;
    obj.fb(sum_fun);
    return 0;
}

Note that the member function fb now takes a single parameter func , which we then call. 注意,成员函数fb现在采用单个参数func ,然后我们调用它。 Note also that in C++17, we now can't instantiate the obj with B obj; 还要注意,在C ++ 17,我们现在不能实例化objB obj; because this would be ambiguous and the template can't be deduced automatically. 因为这将是不明确的,并且模板无法自动推断。 Instead, we need to specify the full type B<void(*)(const double&, const double&)> . 相反,我们需要指定完整类型B<void(*)(const double&, const double&)>

However, a recommended alternative over function pointers is to use std::function , which is more versatile and offers a more readable syntax. 但是,推荐的替代函数指针的替代方法是使用std::function ,它更通用,并提供更易读的语法。 ( std::function Demo ) std::function Demo

In C++17 you're allowed to use auto in template paramter list: 在C ++ 17中,您可以在模板参数列表中使用auto

template <auto F>
class B
{
    public:
    void fb()
    {
        F(10.1,10.2);
    }
};

You can then do B<sum_fun> : 然后你可以做B<sum_fun>

int main()
{
    B<sum_fun> obj{};
    obj.fb();
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM