You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Arduino自定义库编译报错:使用已删除函数问题求助

编译错误解决:TFT_eSPI类赋值运算符被删除问题

问题背景

开发基于Arduino的自定义库,依赖TFT_eSPI库,编译时出现赋值运算符相关错误,且drawGIF函数必须保持静态。

编译错误信息

/.../sketch/src/Display/Display.cpp: In static member function 'static void Display::begin()':
/.../sketch/src/Display/Display.cpp:16:9: error: use of deleted function 'TFT_eSPI& TFT_eSPI::operator=(TFT_eSPI&&)'
tft = TFT_eSPI();
^
In file included from /.../sketch/src/Display/Display.h:12:0,
from /.../sketch/src/Display/Display.cpp:9:
/Users/luigisc/Documents/Arduino/libraries/TFT_eSPI/TFT_eSPI.h:359:7: note: 'TFT_eSPI& TFT_eSPI::operator=(TFT_eSPI&&)' is implicitly deleted because the default definition would be ill-formed:
class TFT_eSPI : public Print {
^
/Users/luigisc/Documents/Arduino/libraries/TFT_eSPI/TFT_eSPI.h:359:7: error: non-static reference member 'fs::FS& TFT_eSPI::fontFS', can't use default assignment operator

相关代码

Display.cpp

#include "Arduino.h"
#include "Display.h"

/*Global objects' declaration and initialization*/

void Display::begin(){
    //Display initializing
    tft = TFT_eSPI();

    tft.fillScreen(TFT_BLACK);
    tft.setTextColor(TFT_WHITE);
    tft.setTextSize(2);
    tft.setRotation(1);

}

// PRIVATE FUNCTIONS

void Display::drawGIF(GIFDRAW *pDraw){
    uint8_t *s;
    uint16_t *d, *usPalette, usTemp[320];
    int x, y, iWidth;

    iWidth = pDraw->iWidth;
    if (iWidth > tft.width())
        iWidth = tft.width();
    usPalette = pDraw->pPalette;
    y = pDraw->iY + pDraw->y; // current line

    s = pDraw->pPixels;
    if (pDraw->ucDisposalMethod == 2) // restore to background color
    {
        for (x=0; x<iWidth; x++)
        {
            if (s[x] == pDraw->ucTransparent)
                s[x] = pDraw->ucBackground;
        }
        pDraw->ucHasTransparency = 0;
    }
    // Apply the new pixels to the main image
    if (pDraw->ucHasTransparency) // if transparency used
    {
        uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
        int x, iCount;
        pEnd = s + iWidth;
        x = 0;
        iCount = 0; // count non-transparent pixels
        while(x < iWidth)
        {
            c = ucTransparent-1;
            d = usTemp;
            while (c != ucTransparent && s < pEnd)
            {
                c = *s++;
                if (c == ucTransparent) // done, stop
                {
                    s--; // back up to treat it like transparent
                }
                else // opaque
                {
                    *d++ = usPalette[c];
                    iCount++;
                }
            } // while looking for opaque pixels
            if (iCount) // any opaque pixels?
            {
                tft.setAddrWindow(pDraw->iX+x, y, iCount, 1);
                tft.startWrite();
                tft.pushPixels(usTemp, iCount);
                tft.endWrite();
                x += iCount;
                iCount = 0;
            }
            // no, look for a run of transparent pixels
            c = ucTransparent;
            while (c == ucTransparent && s < pEnd)
            {
                c = *s++;
                if (c == ucTransparent)
                    iCount++;
                else
                    s--;
            }
            if (iCount)
            {
                x += iCount; // skip these
                iCount = 0;
            }
        }
    }
    else
    {
        s = pDraw->pPixels;
        // Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
        for (x=0; x<iWidth; x++)
            usTemp[x] = usPalette[*s++];
        tft.setAddrWindow(pDraw->iX, y, iWidth, 1);
        tft.startWrite();
        tft.pushPixels(usTemp, iWidth);
        tft.endWrite();
    }
}

// PUBLIC FUNCTIONS

void Display::displayGIF(const uint8_t *gif_file, int gif_size, int nTimes){

    if (gif.open((uint8_t *)gif_file, gif_size, drawGIF)){

        for(int i=0;i<nTimes;i++){
            gif.playFrame(true, NULL);
            while(gif.playFrame(true, NULL)){}
        }

        gif.close();

    }else{
        tft.fillScreen(TFT_BLACK);
        tft.setTextColor(TFT_WHITE);
        tft.setTextSize(2);
        tft.drawString("ERR: Can't load GIF", 0, tft.width()/2);
    }

}   

Display.h

#ifndef DISPLAY_H
#define DISPLAY_H

#include "Arduino.h"
#include <TFT_eSPI.h>
#include <AnimatedGIF.h>

class Display {

  public:
    static void begin();
    static void displayGIF(const uint8_t *gif_file, int gif_size, int nTimes);

  private:
    static void drawGIF(GIFDRAW *pDraw);
    static AnimatedGIF gif;
    static TFT_eSPI tft;

};

#endif

错误原因

TFT_eSPI类包含非静态引用成员fs::FS& fontFS,C++规则中,包含引用成员的类会自动删除默认的赋值运算符(拷贝赋值、移动赋值均被删除)。begin()函数中执行tft = TFT_eSPI();,本质是用临时对象给静态成员tft做移动赋值,触发了被删除的运算符。

解决方法

方案1:直接初始化静态成员(推荐)

静态成员需在类外部初始化,直接创建TFT_eSPI实例,无需在begin()中赋值:

  1. 修改Display.cpp,在文件开头添加静态成员的定义和初始化:
#include "Arduino.h"
#include "Display.h"

// 初始化静态成员
AnimatedGIF Display::gif;
TFT_eSPI Display::tft; // 直接调用默认构造函数初始化

void Display::begin(){
    // 移除 tft = TFT_eSPI(); 这一行
    tft.fillScreen(TFT_BLACK);
    tft.setTextColor(TFT_WHITE);
    tft.setTextSize(2);
    tft.setRotation(1);
}

// 其余代码保持不变
  1. Display.h中的静态成员声明无需修改。

方案2:使用指针动态创建实例(适合动态配置场景)

若需要在begin()中传入参数初始化TFT_eSPI,可改用指针:

  1. 修改Display.h的静态成员声明为指针:
private:
    static void drawGIF(GIFDRAW *pDraw);
    static AnimatedGIF gif;
    static TFT_eSPI* tft; // 改为指针类型
  1. 在Display.cpp中初始化指针并在begin()中创建实例:
#include "Arduino.h"
#include "Display.h"

AnimatedGIF Display::gif;
TFT_eSPI* Display::tft = nullptr; // 初始化为空指针

void Display::begin(){
    if(tft == nullptr){
        tft = new TFT_eSPI(); // 动态创建实例
    }
    tft->fillScreen(TFT_BLACK);
    tft->setTextColor(TFT_WHITE);
    tft->setTextSize(2);
    tft->setRotation(1);
}

// 所有使用tft的地方改为指针调用(->),比如drawGIF函数中的:
// tft->setAddrWindow(...)
// tft->startWrite() 等

方案3:使用std::optional延迟初始化(C++17及以上)

若编译器支持C++17,可用std::optional包装TFT_eSPI:

  1. 修改Display.h:
#include <optional> // 引入头文件

class Display {
private:
    static void drawGIF(GIFDRAW *pDraw);
    static AnimatedGIF gif;
    static std::optional<TFT_eSPI> tft; // 用optional包装
};
  1. 在Display.cpp中初始化并在begin()中构造:
#include "Arduino.h"
#include "Display.h"

AnimatedGIF Display::gif;
std::optional<TFT_eSPI> Display::tft;

void Display::begin(){
    if(!tft.has_value()){
        tft.emplace(); // 构造TFT_eSPI实例
    }
    auto& tft_ref = *tft; // 获取引用方便后续调用
    tft_ref.fillScreen(TFT_BLACK);
    tft_ref.setTextColor(TFT_WHITE);
    tft_ref.setTextSize(2);
    tft_ref.setRotation(1);
}

注意事项

  • 方案1最简洁高效,符合Arduino编程习惯,优先选择。
  • 使用方案2时,可在程序结束时手动delete tft;避免内存泄漏(Arduino平台通常无需处理,但严谨起见可添加)。
  • drawGIF函数保持静态不受影响,静态成员的访问权限不受函数静态性限制。

内容的提问来源于stack exchange,提问作者Luigi Schiavone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 02:41:06