【问题标题】:Pass templated function to std::function [duplicate]将模板化函数传递给 std::function [重复]
【发布时间】:2022-01-30 06:05:31
【问题描述】:

Check it out at godbolt

#include <complex>
#include <functional>
#include <iostream>
#include <vector>

using Complex = std::complex<double>;

using namespace std::literals::complex_literals;

struct S
{
    std::vector<Complex> data;
    S& apply(std::function<Complex(Complex const&)> f)
    {
        for( auto& elem : data )
        {
            elem = f(elem);
        }
        return *this;
    }
};

int main()
{
    S s{{1.i,-2.i,3.i}};
    s.apply(std::conj); // error 
    return EXIT_SUCCESS;
}

错误:无法将 '' 转换为 'std::function<:complex>(const std::complex&)>'

现在一个解决方法是使用 lambda 或定义非模板函数。是否有另一种方法可以指定模板以便将std::conj 传递给std::function?

【问题讨论】:

  • 获取(几乎)任何标准函数的地址都是UB,所以无论如何你都需要包装它。

标签: c++ templates function-pointers


【解决方案1】:

您可以为常规函数指针重载。

struct S
{
    std::vector<Complex> data;
    using CB = Complex(Complex const&);
    S& apply(std::function<CB> f)
    {
        for( auto& elem : data )
        {
            elem = f(elem);
        }
        return *this;
    }
    S& apply(CB* cb) { return apply(std::function(cb)); }
};

std::function 通过其构造函数模板接受。所以一个重载集不能被它解决。但是一个普通的函数指针可以通过推导它的具体类型来描述一个重载集。

但有一个警告。该标准通常不允许获取标准库函数(或特化)的地址,除非它们被明确标记为“可寻址函数”。这就是它未来证明自己的方式,以便可以在未来的修订中添加重载,而不会破坏遵循合同的现有代码。

通常仅出于这个原因建议使用 lambda。

【讨论】:

    【解决方案2】:

    std::conj() 是一个重载函数。将std::conj 传递给您的函数时,您必须指定实际需要的重载,例如:

    s.apply(static_cast<Complex (*)(const Complex&)>(std::conj));
    

    Online Demo

    或者:

    Complex (*func)(const Complex&) = std::conj;
    s.apply(func);
    

    Online Demo

    另请参阅 cppreference.com 上的 Address of an overloaded function

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-17
      • 2017-06-09
      • 1970-01-01
      • 1970-01-01
      • 2018-03-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多