I'm currently struggling to convert fmt::format_string<Args...>to a std::string_view.
The idea: I would like to create a fucntion with can be called from an ISR and task context. However in an ISR no dynamic memory allocation is allowed. That's why i cannot call fmt::fomat() in this case. However I'm getting a strange compiler error
<source>(67): error C7595: 'fmt::v9::basic_format_string<char>::basic_format_string': call to immediate function is not a constant expression
Here is a minimal working example
#include <fmt/format.h>
#include <string>
#include <string_view>
#include <source_location>
#include <concepts>
#include <cassert>
class DebugQueue
{
public:
bool addToTaskQueue(
std::string& strMessage,
std::string& strCategeory,
const std::source_location loc
)
{
return false;
};
bool addToISRQueue(
const std::string_view strFormatedDebugMessage,
const std::string_view strCategory,
const std::source_location loc)
{
return false;
};
};
class Log
{
public:
template <typename... Args>
bool logAsync(
fmt::format_string<Args...> fmt,
const std::string_view strCategory,
Args&&... args
);
template <typename String_T>
bool logAsync(
String_T& strFormatedDebugMessage,
String_T& strCategory,
const std::source_location loc = std::source_location::current()
);
static bool inHandlerMode();
private:
DebugQueue m_queue;
};
bool Log::inHandlerMode()
{
return false;
}
template<typename ...Args>
bool Log::logAsync(
fmt::format_string<Args...> fmt,
const std::string_view strCategory,
Args&&... args)
{
//if called from ISR we cannot call formatting functions since they will implicitly call new
bool bRes = false;
if (inHandlerMode())
{
fmt::basic_string_view<char> asStringView = fmt;
bRes = logAsync(std::string_view(asStringView.data()), strCategory);
}
else
{
std::string strFormatedMessage = fmt::format(fmt, std::forward<Args>(args)...);
std::string strCat(strCategory);
bRes = logAsync(strFormatedMessage, strCat);
}
}
template<typename String_T>
bool Log::logAsync(
String_T& strFormatedDebugMessage,
String_T& strCategory,
const std::source_location loc)
{
bool bRes = false;
if (inHandlerMode())
{
//called from ISR, do not use any dynamic memory allocation
//just add the unformated message to the queue
bRes = m_queue.addToISRQueue(strFormatedDebugMessage, strCategory, loc);
}
else
{
//called from Task Context
std::string strMsg;
std::string strCat;
if constexpr (std::same_as<std::string, String_T>)
{
std::swap(strMsg, strFormatedDebugMessage);
std::swap(strCategory, strCat);
}
else
{
strMsg = std::string(strFormatedDebugMessage.data());
strCategory = std::string(strCat.data());
}
bRes = m_queue.addToTaskQueue(strFormatedDebugMessage, strCategory, loc);
}
}
static Log g_log;
int main() {
fmt::print("The answer is {}.", 42);
g_log.logAsync("Info {}", "fooCat",1);
g_log.logAsync("Info", "fooCat");
}
https://godbolt.org/z/d7jeTjT6f
thx for your help guys :)
as suggested by @user17732522 in the comments the answer is changing String_T& to String_T and renaming
template <typename String_T>
bool logAsync(
String_T& strFormatedDebugMessage,
String_T& strCategory,
const std::source_location loc = std::source_location::current()
);
to
template <typename String_T>
bool _logAsync(
String_T& strFormatedDebugMessage,
String_T& strCategory,
const std::source_location loc = std::source_location::current()
);
did solve my problem. Thx guys for your help:)