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

时间:2019-08-01 00:32:08

标签: c++ templates

我试图将函数作为模板参数传递给类中的函数,但是存在一些错误。代码给出错误error: missing template arguments before 'obj'。我该如何解决它以便编译?

#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;
}

2 个答案:

答案 0 :(得分:3)

对类的工作方式有误解。

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;
}

两行都引发错误

  1. 您的类没有使用单个参数的构造函数。
  2. void fb()(F f1)是非法语法。要声明成员函数,请仅使用一组括号:void fb()void fb(F f1)。在我们的情况下,后者是不正确的,因为您的成员函数调用obj.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;

};

在C ++ 17中,由于可以自动进行模板推导,因此现在不会发出任何错误。但是在较低的标准(例如C ++ 11)中,缺少模板推导,因此在声明obj时需要指定完整的模板化类型。

因此在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;
}

此处,double(*)(const double&, const double&)function pointer,即指向函数的指针,该函数返回double并接受两个类型均为const double&的参数。函数指针可以被视为满足模板(template<typename F>)的类型。

就像我们做std::vector<int>std::vector<double>一样,我们也可以做std::vector<double(*)(const double&, const double&)>来表示返回double并以const double&作为参数的函数向量。

顺便说一句,sum_fun也引发了警告:即使返回类型为double,也不会返回任何内容...最好将void指定为返回类型。

C++11 Demo
C++17 Demo


  

是否可以将函数作为参数直接传递给B::fb()而不是创建构造函数B::B(F)并存储在局部变量中?

当然。

#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;
}

请注意,成员函数fb现在采用单个参数func,然后我们将其调用。还要注意,在C ++ 17中,我们现在无法用obj实例化B obj;,因为这将是模棱两可的,并且无法自动推导模板。相反,我们需要指定完整类型B<void(*)(const double&, const double&)>

但是,建议使用函数指针替代std::function,它更通用并且提供了更易读的语法。 (std::function Demo

答案 1 :(得分:0)

在C ++ 17中,允许在模板参数列表中使用auto

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

然后您可以执行B<sum_fun>

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