【问题标题】:"undefined reference" for lambda function to process multiple template classes用于处理多个模板类的 lambda 函数的“未定义引用”
【发布时间】:2021-06-24 15:43:51
【问题描述】:

我有一个这样的模板类:

Strip.h

#pragma once

class IStrip
{
public:
    int Pin;

    void compute();
};

template <int PIN>
class Strip : public IStrip
{
public:
    int Pin = PIN;

    void compute()
    {

    }
};

我像这样管理它们的多个实例:

Manager.h

#pragma once

#include "Strip.h"

class Manager
{
private:
    Strip<12> inst12;
    Strip<13> inst13;

    template <typename Func>
    void each(Func f)
    {
        f(inst12);
        f(inst13);
    }

    void computeData()
    {
        each([](IStrip sm)
             { sm.compute(); });
    }
};

现在,每当我调用 computeData() 时,我想将一些逻辑应用于我的所有实例,如 each(Func f) 所示,但是,每当我编译时,我都会收到:

.pio\main.cpp.o:(.literal._ZN6Strips4loopEv[Strips::loop()]+0x14): undefined reference to `IStrip::compute()'
.pio\main.cpp.o: In function `Strips::computeData()::{lambda(IStrip*)#1}::operator()(IStrip*) const':
.pio\libdeps\az-delivery-devkit-v4\FastLED\src/controller.h:171: undefined reference to `IStrip::compute()'

当我把computeData的函数体改成:

each([](auto sm)
     { sm.compute(); });

并使用-std=gnu++14 编译,它神奇地工作,但是,当尝试调用compute() 时,程序毫无例外地停止。

我错过了一个重要的细节吗?提前致谢。

【问题讨论】:

    标签: c++ templates lambda


    【解决方案1】:

    你错过了很多。首先IStrip 类或Strip 类模板不是多态的。通过将 sm 按值传递给 lambda,您就有了对象 slicing

    要让它工作,你首先需要使IStrip::compute成为一个纯虚函数:

    class IStrip
    {
    public:
        virtual void compute() = 0;
    };
    

    那么你需要通过引用lambda函数来传递对象:

    each([](IStrip& sm)
             { sm.compute(); });
    

    Strip::compute 函数必须是纯函数,否则必须定义(实现)它。


    您当前的代码现在发生的情况是您尝试调用IStrip::compute(),这确实没有定义(实现)。

    当您使用auto 参数推导时,编译器会推断您传递了一个Strip&lt;X&gt; 对象,该对象定义了其compute 函数。

    【讨论】:

    • 感谢您提供有关 auto 的更多详细信息。我从一开始就尝试使用 virtual,但是我的应用程序的其他部分正在停止执行,我错误地认为是因为这个。我仍在尝试理解某些语法部分,因为我几天前才开始使用 cpp。当之无愧的接受答案!
    【解决方案2】:

    您的第一次尝试会导致未定义的行为。

    class IStrip
    {
    public:
        int Pin;
    
        void compute();
    };
    

    声明IStrip::compute() 函数,但从未定义它。稍后,当 lambda

        each([](IStrip sm)
             { sm.compute(); });
    

    被调用,你最终将 slicing Strip 对象变为 ISlip 并尝试调用从未定义的函数 - 因此,你有未定义的引用问题。

    这个问题的最佳解决方案是,将IStrip::compute() 声明为纯虚拟,以实现早期检测和有意义的诊断。

    编译器会提醒您尝试创建抽象类的实例,这会提示您将 lambda 更改为

        each([](IStrip& sm)
             { sm.compute(); });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-10
      • 2012-02-03
      • 2014-04-30
      • 2018-07-14
      • 2015-10-12
      相关资源
      最近更新 更多