Compile error in Flash library header file

Hello, Can you please help me solve a compile error in this Flash library.

Library description:
An Arduino library for smoother, easier access to Flash data. This fork from MikalHart is the 1.5+ compatible version, and officially added to the Arduino library manager.

There are two compile errors:

  1. no matching function for call to 'print(ostream& (*&)(ostream&))'
  2. invalid conversion from 'ostream& (*)(ostream&)' to 'long unsigned int' [-fpermissive

Both errors occur on line #240 of Flash.h.

Computer System:

  • Windows 10 Pro x64.
  • PlatformIO Core 5.2.5 Home 3.4.1.
  • Arduino IDE 1.8.19 portable.

main.cpp:

#include <Arduino.h>
#include <Flash.h>

I'm struggling to understand exactly why the compiler is giving the invalid conversion error. I'm a little familiar with templates and operator overloading but it's beyond my knowledge to understand how the overload function(s) are defined.
I would really appreciate help in understanding what's going on and how the overload operator calls the correct type to stream.

If needs be I can create a bare minimum test project to illustrate the issue but since it appears to be a library issue I haven't not yet done so.

I would warmly welcome your input.

Flash.h:

/*
  Flash.h - An Arduino library for flash-based (ROM) data collections.
  Copyright (C) 2009-2012 Mikal Hart
  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
#ifndef __FLASH_H__
#define __FLASH_H__

#include <avr/pgmspace.h>
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#define FLASH_LIBRARY_VERSION 5

// Use these macros to define your flash-based data structures
// Example: FLASH_STRING(str, "Four score and seven years ago");
#define FLASH_STRING(name, value) \
  static const char name##_flash[] PROGMEM = value; \
  _FLASH_STRING name(name##_flash);

// Example: FLASH_ARRAY(float, temperatures, 98.1, 98.5, 99.1, 102.1);
#define FLASH_ARRAY(type, name, values...) \
  static const type name##_flash[] PROGMEM = { values }; \
  _FLASH_ARRAY<type> name(name##_flash, sizeof(name##_flash) / sizeof(type));

// Example: FLASH_TABLE(uint8_t, fonts, 7, {ON, OFF, ON, ON, OFF, ON, OFF}, {OFF, ON, OFF, ON, OFF, ON, OFF});
#define FLASH_TABLE(type, name, cols, values...) \
  static const type name##_flash[][cols] PROGMEM = { values }; \
  _FLASH_TABLE<type> name((const PROGMEM type *)name##_flash, sizeof(name##_flash) / sizeof(name##_flash[0]), cols);

// Example: FLASH_STRING_ARRAY(nums, PSTR("One"), PSTR("Two"), PSTR("Three"), PSTR("Four"), PSTR("Five"));
#define FLASH_STRING_ARRAY(name, values...) \
  const char *name##_arr[] PROGMEM = { values }; \
  _FLASH_STRING_ARRAY name(name##_arr, sizeof(name##_arr) / sizeof(name##_arr[0]));

#ifndef ARDUINO_CORE_PRINTABLE_SUPPORT
class _Printable
{
public:
  virtual void print(Print &stream) const = 0;
};
#endif

#if ARDUINO < 100
// Inline ROM strings.  Example: Serial << F("Hello, big world!");
#define F(str) (_FLASH_STRING(PSTR(str)).Printable())
#endif

/* _FLASH_STRING class.  Use the FLASH_STRING() macro to create these, or use inline F() macro. */
class _FLASH_STRING : public _Printable
{
public:
#if ARDUINO >= 150
  _FLASH_STRING(const char *arr PROGMEM);
#else
  _FLASH_STRING(const prog_char *arr);
#endif

  size_t length() const 
  { return strlen_P(_arr); }

  char *copy(char *to, size_t size = -1, size_t offset = 0) const 
  { 
#if ARDUINO >= 150
    return size == (size_t)-1 ?
#else
    return size == -1 ?
#endif
      strcpy_P(to, _arr + offset) : strncpy_P(to, _arr + offset, size);
  }

#if ARDUINO >= 150
  const char *access() const PROGMEM { return _arr; }
#else
  const prog_char *access() const { return _arr; }
#endif

  const _Printable &Printable() const
  { return *this; }

  char operator[](int index) const
  { return static_cast<char>(pgm_read_byte(_arr + index)); }

  void print(Print &stream) const;

private:
#if ARDUINO >= 150
  const char *_arr PROGMEM;
#else
  const prog_char *_arr;
#endif
  
};

/* _FLASH_ARRAY template class.  Use the FLASH_ARRAY() macro to create these. */
template<class T>
class _FLASH_ARRAY : public _Printable
{
#if ARDUINO >= 150
  typedef const T PROGMEM _DataType;
#else
  typedef T PROGMEM _DataType;
#endif

public:
  _FLASH_ARRAY(const _DataType *arr, size_t count) : _arr(arr), _size(count)
  { }

  size_t count() const 
  { return _size; }

  const _DataType *access() const 
  { return _arr; }

  T operator[](int index) const
  {
    uint32_t val = 0;
    if (sizeof(T) == 1)
      val = pgm_read_byte(_arr + index);
    else if (sizeof(T) == 2)
      val = pgm_read_word(_arr + index);
    else if (sizeof(T) == 4)
      val = pgm_read_dword(_arr + index);
    return *reinterpret_cast<T *>(&val);
  }

  void print(Print &stream) const
  {
    for (size_t i=0; i<_size; ++i)
    {
      stream.print((*this)[i]);
      if (i < _size - 1) 
        stream.print(",");
    }
  }

private:
  const _DataType *_arr;
  size_t _size;
};

/* _FLASH_TABLE template class.  Use the FLASH_TABLE() macro to create these. */
template<class T>
class _FLASH_TABLE : public _Printable
{
  typedef T PROGMEM _DataType;

public:
  _FLASH_TABLE(const _DataType *arr, size_t rows, size_t cols) : _arr(arr), _rows(rows), _cols(cols)
  { }

  size_t rows() const 
  { return _rows; }

  size_t cols() const 
  { return _cols; }

  const _DataType *access() 
  { return _arr; }

  _FLASH_ARRAY<T> operator[](int index) const
  {
    _FLASH_ARRAY<T> row(_arr + index * _cols, _cols);
    return row;
  }

  void print(Print &stream) const
  {
    for (int i=0; i<_rows; ++i)
    {
      _FLASH_ARRAY<T> row(_arr + i * _cols, _cols);
      row.print(stream);
      stream.println();
    }
  }

private:
  const _DataType *_arr;
  size_t _rows, _cols;
};

/* _FLASH_STRING_ARRAY class.  Use the FLASH_STRING_ARRAY() macro to create these. */
class _FLASH_STRING_ARRAY : public _Printable
{
public:
#if ARDUINO >= 150
  _FLASH_STRING_ARRAY(const char **arr PROGMEM, size_t count) : _arr(arr), _size(count) {}
#else
  _FLASH_STRING_ARRAY(const prog_char **arr, size_t count) : _arr(arr), _size(count) {}
#endif

  size_t count() const 
  { return _size; }

  _FLASH_STRING operator[](int index) const
  { return _FLASH_STRING(_arr[index]); }

  void print(Print &stream) const
  {
    for (size_t i=0; i<_size; ++i)
    {
      _FLASH_STRING str(_arr[i]);
      str.print(stream);
      stream.println();
    }
  }

private:
#if ARDUINO >= 150
  const char **_arr PROGMEM;
#else
  const prog_char **_arr;
#endif
  
  size_t _size;
};

#ifndef ARDUINO_STREAMING
#define ARDUINO_STREAMING

template<class T> 
inline Print &operator <<(Print &stream, T arg) 
{ stream.print(arg); return stream; }

#endif

inline Print &operator <<(Print &stream, const _Printable &printable) 
{ printable.print(stream); return stream; }

inline Print &operator <<(Print &stream, const _FLASH_STRING &printable) 
{ printable.print(stream); return stream; }

template<class T> 
inline Print &operator <<(Print &stream, const _FLASH_ARRAY<T> &printable) 
{ printable.print(stream); return stream; }

template<class T> 
inline Print &operator <<(Print &stream, const _FLASH_TABLE<T> &printable) 
{ printable.print(stream); return stream; }

inline Print &operator <<(Print &stream, const _FLASH_STRING_ARRAY &printable) 
{ printable.print(stream); return stream; }

#endif // def __FLASH_H__

Flash.cpp:

/*
  Flash.cpp - An Arduino library for flash-based (ROM) data collections.
  Copyright (C) 2009 Mikal Hart
  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "Flash.h"
#if ARDUINO >= 150
  _FLASH_STRING::_FLASH_STRING(const char *arr PROGMEM) : _arr(arr) {}
#else
  _FLASH_STRING::_FLASH_STRING(const prog_char *arr) : _arr(arr) {}
#endif

void _FLASH_STRING::print(Print &stream) const
{
  for (size_t i=0; ; ++i)
  {
    char c = (*this)[i];
    if (!c) break;
    stream.print(c); // print in char form
  }
}

it is a template so T is the type you use to call the operator. how do you use << ?

Juraj, thanks for your reply. So you think the compile error could be due to usage rather than an issue with the Flash library.

Because the project uses a lot of static data the flash library is used to conserve RAM by storing data in PROGMEM. There are various data types, int and C strings. Typical usage is:

Serial << F("Character String ( length: ") << stringLength << ")\r\n"; // stringLength 16bit integer

Because the compile error pin-pointed the Flash.h I thought the library was the issue. I will create a small test project tomorrow to narrow down the 'variables'.

what is ostream? it looks like if Print was a preprocessor macro for ostream.
is there somewhere #define Print ostream?
the library is for AVR MCU. do you have some other MCU?
or do you compile for some PC mock of an MCU?

Juraj, the MCU is an AVR, it's an Atmega2560. The ostream class is not defined in the Flash library, but it is defined in SdFat library which is also part of this project. So I think you have identified the issue. I'm going to make up a test project and add the libraries in until I find the issue.
The project was originally built years ago with the MS Arduino plug in for VSCode which I've now moved to PlatformIO - I have a hunch that somehow PlatformIO has included a incompatible library or an incompatible version.
I will report back after further investigations, many thanks for your input it's got the attention flowing in the right direction now.

I have dropped using the Flash library and instead used this streaming library. This then generated this compiler error:

[{
	"resource": "/a:/Arduino/Projects/Weather/BaseStation-LCD12864/.pio/libdeps/megaatmega2560/SdFat@1.0.5/src/FatLib/iostream.h",
	"owner": "cpp",
	"severity": 8,
	"message": "'ostream& endl(ostream&)' redeclared as different kind of symbol",
	"startLineNumber": 45,
	"startColumn": 33,
	"endLineNumber": 45,
	"endColumn": 33
}]
[{
	"resource": "/a:/Arduino/Projects/Weather/BaseStation-LCD12864/lib/Streaming/Streaming.h",
	"owner": "cpp",
	"severity": 8,
	"message": "'endl' redeclared as different kind of symbol",
	"startLineNumber": 177,
	"startColumn": 21,
	"endLineNumber": 177,
	"endColumn": 21
}]

googling discovered this issue is already known. Commenting out inline ostream& endl(ostream& os) { has solved the problem, at least the project compiles without errors now. Not sure about the ramifications though.
Thanks again Juraj, your input was helpful, just what was needed.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.