【问题标题】:Calling member function in transform()在 transform() 中调用成员函数
【发布时间】:2020-06-03 23:00:19
【问题描述】:

所以我一直在尝试使用变换函数从 2 个现有的向量中创建一个向量。我成功地设法在没有类的情况下做到了,但现在我想使用类,但我得到了错误。下面的代码只是我项目的一小部分相关部分,所以它可能看起来很傻,但整个事情最终实际上是有意义的。

这是我的头文件的一部分:

#include <vector>
#include <algorithm>

class Example
{
public:
    double multiply(double x, double y);
    void generate_amplitude(std::vector<double>& ampVec);
};

还有我的 .cpp 文件的一些内容:

#include "example.h"

double Example::multiply(double x, double y)
{
    return x*y;
}

void Example::generate_amplitude(std::vector<double>& ampVec)
{
    double const a = 3.14;
    int const lenVectors = 10;

    std::vector<double> timeVec = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9}
    std::vector<double> ampVec(lenVectors);
    std::vector<double> aVec(lenVectors, a);

    // Fill ampVec with timeVec[i]*aVec[i] for i in range[0:lenVectors[
    transform(timeVec.begin(), timeVec.end(), aVec.begin(), ampVec.begin(), multipy);
}

所以当我尝试编译时,我得到:

error: must use '.*' or '-&gt;*' to call pointer-to-member function in '__binary_op (...)', e.g. '(... -&gt;* __binary_op) (...)'

我确实搜索并阅读了几个小时关于指向成员函数的内容,尝试了几种不同的方法,例如:

double (Example::*pmf)(double, double);
pmf = &Example::multiply;
transform(timeVec.begin(), timeVec.end(), aVec.begin(), ampVec.begin(), this->*pmf);

但我还是新手,无法找到让它发挥作用的方法。这个特殊的例子返回了那种消息:

error: no matching function for call to 'transform(std::vector<double>::iterator, std::vector<double>::iterator, std::vector<double>::iterator, std::vector<double>::iterator, double (Example::)(double, double))'
note: candidate: 'template<class _IIter, class _OIter, class _UnaryOperation> _OIter std::transform(_IIter, _IIter, _OIter, _UnaryOperation)'
note:   candidate expects 4 arguments, 5 provided
note:   template argument deduction/substitution failed
note: candidate: 'template<class _IIter1, class _IIter2, class _OIter, class _BinaryOperation> _OIter std::transform(_IIter1, _IIter1, _IIter2, _OIter, _BinaryOperation)'
note:   member function type 'double (Example::)(double, double)' is not a valid template argument

非常感谢您的帮助!

【问题讨论】:

    标签: c++ vector transform pointer-to-member


    【解决方案1】:

    解决此问题的最简单方法是使用 lambda:

    transform(
        timeVec.begin(), timeVec.end(),
        aVec.begin(),
        ampVec.begin(),
        [this](double a, double b) { return multiply(a, b); }
    );
    

    您不能在此处使用指向成员函数的指针,因为您需要 this 指针来调用指向成员函数的指针,而 std::transform() 没有提供此信息的机制。使用 lambda 捕获它通过使 this 成为函子状态的一部分来解决该问题。

    您可以通过编写自定义函子在 C++03 中做类似的事情:

    class ExampleMultiply {
    public:
        explicit ExampleMultiply(Example &p) : example(p) {}
    
        double operator()(double a, double b) const {
            return example.multiply(a, b);
        }
    
    private:
        Example &example;
    };
    

    然后用这个函子调用std::transform()

    transform(
        timeVec.begin(), timeVec.end(),
        aVec.begin(),
        ampVec.begin(),
        ExampleMultiply(*this)
    );
    

    在底层,这基本上是编译器为实现 lambda 表达式而生成的内容。

    【讨论】:

    • 您可以使用 std::bind 代替显式 lambda:std::bind(&Example::multiply, this, std::placeholder::_1, std::placeholder::_2)
    • @SornelHaetir 确实如此。就我个人而言,我更喜欢 lambdas 而不是 std::bind()(我觉得 lambdas 有点多余,而且占位符对我来说有点冗长)但它肯定会起作用。用 C++ 完成同样的事情的方法不乏,这是肯定的。
    • 我确实使用了 lambdas 解决方案,它就像一个魅力。然而,经过一些测试后,我发现使用 for 循环填充我的 ampVec 平均比使用变换函数快......知道为什么吗?我之所以选择这种方式,正是因为我认为现有的专用函数会更快。
    • @Zeloon 您可能想为此打开一个新问题,以便我们可以看到您用于循环和transform 方法的代码。我们还需要确切了解您是如何进行基准测试的。 C++ 很难进行基准测试,因为编译器非常聪明,实际上可能会从基准测试中删除在生产环境中使用时不会删除的代码。
    猜你喜欢
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 2011-04-02
    • 2011-01-18
    相关资源
    最近更新 更多