I am facing a little problem.
I need to use spdlog to log and I have custom classes.
And since, spdlog is able to deal with user defined classes, I could use it log my classes.
But, I my real application, I would like to feed spdlog with a pointer of my class (because there is polymorphism but it's not the point here).
And here goes my troubles.
When I try to feed spdlog with a unique_ptr of my class, it does not compile.
So here a MWE:
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string.h>
#include <spdlog/spdlog.h> //
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/fmt/ostr.h" // must be included to log object
using namespace std;
struct my_type
{
int i;
template<typename OStream>
friend OStream &operator<<(OStream &os, const my_type &c)
{
return os << "[my_type i=" << c.i << "]";
}
};
template<typename OStream>
OStream &operator<<(OStream &os,const my_type* c)
{
return os << "[my_type i=" << "pointer" << "]";
}
int main() {
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
spdlog::logger logger("log_test", console_sink);
logger.set_level(spdlog::level::trace);
auto pLog =std::make_shared<spdlog::logger>(logger); //register it if you need to access it globally
std::unique_ptr<my_type> ptrA(new my_type{12});
pLog->info("user defined type: {}", ptrA); // of course *ptrA simply works, but in my application I have to give ptrA ...
return 0;
}
and I get errors from the compiler gcc:
spdlog/fmt/bundled/core.h:1566:15: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = my_type; _Dp = std::default_delete<my_type>]’
const auto& arg = arg_mapper<Context>().map(val);
spdlog/fmt/bundled/core.h:1567:3: error: static assertion failed: Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt
static_assert(
spdlog/fmt/bundled/core.h:1184:15: error: use of deleted function ‘fmt::v8::detail::fallback_formatter<T, Char, Enable>::fallback_formatter() [with T = fmt::v8::detail::unformattable; Char = char; Enable = void]’
Formatter f;
^
/spdlog/fmt/bundled/core.h:963:3: note: declared here
fallback_formatter() = delete;
^~~~~~~~~~~~~~~~~~
spdlog/fmt/bundled/core.h:1185:28: error: ‘struct fmt::v8::detail::fallback_formatter<fmt::v8::detail::unformattable, char, void>’ has no member named ‘parse’
parse_ctx.advance_to(f.parse(parse_ctx));
~~^~~~~
spdlog/fmt/bundled/core.h:1186:22: error: ‘struct fmt::v8::detail::fallback_formatter<fmt::v8::detail::unformattable, char, void>’ has no member named ‘format’
ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
~~^~~~~~
I guess the problem is comming from the interaction between template<typename OStream> OStream &operator<<(OStream &os,const my_type* c) and spdlog or fmt. So I tried to play a bit around but I am stuck.
Do you have ideas to solve this problem, keeping pLog->info("user defined type: {}", ptrA); ?
The problem comes from the library fmt since version 8 (used by spdlog since version 1.9.0), pointers are no longer supported.
A solution can be to use a wrapper class to store the pointer and precise how fmt should deal with it.
Related
For some reason boost::test can't manage to compile the following code
#define BOOST_TEST_MODULE EPUTests
#include <iostream>
#include <boost/test/unit_test.hpp>
using epu8 = uint8_t __attribute__((vector_size(16)));
std::ostream &operator<<(std::ostream &stream, epu8 const &term) {
stream << "[" << unsigned(term[0]);
for (unsigned i = 1; i < 16; ++i)
stream << "," << unsigned(term[i]);
stream << "]";
return stream;
}
bool failtest(epu8 x) { return false; }
//****************************************************************************//
BOOST_AUTO_TEST_SUITE(EPU8_test)
BOOST_AUTO_TEST_CASE(EPU8_equal) {
epu8 x {};
BOOST_CHECK_PREDICATE(failtest, (x));
}
BOOST_AUTO_TEST_SUITE_END()
//****************************************************************************//
The error message is
In file included from /usr/include/boost/test/tools/floating_point_comparison.hpp:21:0,
from /usr/include/boost/test/tools/old/impl.hpp:21,
from /usr/include/boost/test/test_tools.hpp:46,
from /usr/include/boost/test/unit_test.hpp:18,
from boost_test_epu.cpp:4:
/usr/include/boost/test/tools/detail/print_helper.hpp: In instantiation of 'struct boost::test_tools::tt_detail::print_log_value<__vector(16) unsigned char>':
/usr/include/boost/test/tools/detail/print_helper.hpp:178:5: required from 'std::ostream& boost::test_tools::tt_detail::operator<<(std::ostream&, const boost::test_tools::tt_detail::print_helper_t<T>&) [with T = __vector(16) unsigned char; std::ostream = std::basic_ostream<char>]'
/usr/include/boost/test/utils/lazy_ostream.hpp:66:29: required from 'std::ostream& boost::unit_test::lazy_ostream_impl<PrevType, T, StorageT>::operator()(std::ostream&) const [with PrevType = boost::unit_test::lazy_ostream; T = boost::test_tools::tt_detail::print_helper_t<__vector(16) unsigned char>; StorageT = const boost::test_tools::tt_detail::print_helper_t<__vector(16) unsigned char>&; std::ostream = std::basic_ostream<char>]'
boost_test_epu.cpp:29:1: required from here
/usr/include/boost/test/tools/detail/print_helper.hpp:47:5: error: static assertion failed: Type has to implement operator<< to be printable
BOOST_STATIC_ASSERT_MSG( (boost::has_left_shift<std::ostream,T>::value),
I understand that g++ is complaining that my epu8 type is not printable. However I know it is because changing
BOOST_CHECK_PREDICATE(failtest, (x));
by
std::cout << x << std::endl;
BOOST_CHECK(failtest(x));
works as expected and print by vector variable correctly.
The same error is reported with various version of clang++ and g++
What am I doing wrong ?
BOOST::test requires the console output operator<< to be in the std namespace
namespace std
{
ostream &operator<<(...)
...
}
I'm trying to export some C++11 functionality to R, using Rcpp. Some of these functions return their result using a std::unique_ptr. This stuff cannot be copied. The MCVE below uses std::unique_ptr<std::string> to illustrate the errors.
I have created a class around the unique_ptr, in the hopes of making all of this possible, but to no avail. This is the PtrClassOwner below. The function createClassWrapper calls the original createClass, to stick the unique_ptr in a PtrClassOwner object.
#include <RcppCommon.h>
#include <memory>
#include <string>
// Stuff to wrap:
using PtrClass = std::unique_ptr<std::string>;
PtrClass createClass() { return PtrClass{new std::string("boo")}; }
// ---
class PtrClassOwner {
public:
PtrClass string;
};
PtrClassOwner createClassWrapper() { return PtrClassOwner{createClass()}; }
RCPP_EXPOSED_WRAP(PtrClassOwner); // Rcpp-extending vignette says RCPP_EXPORT_WRAP, which doesn't exist.
RCPP_EXPOSED_AS(PtrClassOwner);
#include <Rcpp.h>
RCPP_MODULE(Class){
using namespace Rcpp;
class_<PtrClassOwner>("PtrClass");
function("createClass", &createClassWrapper);
}
This the first error reported by GCC (v 5.4, on Linux):
In file included from /home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/RcppCommon.h:195:0,
from rcpp_module.cpp:1:
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/internal/wrap.h: In instantiation of ‘SEXPREC* Rcpp::internal::wrap_dispatch(const T&, Rcpp::traits::wrap_type_module_object_tag) [with T = PtrClassOwner; SEXP = SEXPREC*]’:
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/internal/wrap_end.h:30:38: required from ‘SEXPREC* Rcpp::wrap(const T&) [with T = PtrClassOwner; SEXP = SEXPREC*]’
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/internal/wrap_end.h:35:20: required from ‘SEXPREC* Rcpp::module_wrap_dispatch(const T&, Rcpp::traits::normal_wrap_tag) [with T = PtrClassOwner; SEXP = SEXPREC*]’
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/internal/wrap.h:922:40: required from ‘SEXPREC* Rcpp::module_wrap(const T&) [with T = PtrClassOwner; SEXP = SEXPREC*]’
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/module/Module_generated_CppFunction.h:34:50: required from ‘SEXPREC* Rcpp::CppFunction0<RESULT_TYPE>::operator()(SEXPREC**) [with RESULT_TYPE = PtrClassOwner; SEXP = SEXPREC*]’
rcpp_module.cpp:26:1: required from here
/home/cris/R/x86_64-pc-linux-gnu-library/3.2/Rcpp/include/Rcpp/internal/wrap.h:759:54: error: use of deleted function ‘PtrClassOwner::PtrClassOwner(const PtrClassOwner&)’
return Rcpp::internal::make_new_object<T>(new T(object));
^
rcpp_module.cpp:9:7: note: ‘PtrClassOwner::PtrClassOwner(const PtrClassOwner&)’ is implicitly deleted because the default definition would be ill-formed:
class PtrClassOwner {
^
The problem seems to be that, to wrap the object into an R object, it needs to be copied. This other question is from someone running into a similar issue, but there are no answers.
I have created a similar interface to Python, where the Python object just contains a pointer to the C++ object. I find it strange that Rcpp tries to copy the object to wrap it.
Is there a way around this issue? Is it possible to wrap only a pointer to the object in an R type, and somehow still properly manage its lifetime? I'm open to any solutions, I'm not set on using Rcpp, it just seemed the most straightforward method to export this functionality.
The simplest solution I've found so far is to extract the pointer from the std::unique_ptr and create a std::shared_ptr from it. Rcpp will wrap this, as it can be copied.
#include <Rcpp.h>
#include <memory>
#include <string>
// Stuff to wrap:
using PtrClass = std::unique_ptr<std::string>;
PtrClass createClass() { return PtrClass{new std::string("boo")}; }
// ---
using ShPtrClass = std::shared_ptr<PtrClass::element_type>;
class PtrClassOwner {
public:
ShPtrClass shPtrClass;
PtrClassOwner(PtrClass ptr) : shPtrClass(ptr.release()) {}
};
PtrClassOwner createClassWrapper() { return PtrClassOwner{createClass()}; }
std::string getString(PtrClassOwner const& ptr) {
return *(ptr.shPtrClass);
}
RCPP_EXPOSED_CLASS(PtrClassOwner);
RCPP_MODULE(Class){
using namespace Rcpp;
class_<PtrClassOwner>("PtrClass");
function("createClass", &createClassWrapper, "createClass method");
function("getString", &getString, "getString method");
}
How to add object of class to vector in another class.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class info{
private:
int id;
string name;
public:
info(int extId, string extName) {
this->id = extId;
this->name = extName;
}
};
class db {
private:
vector<info> infoVector;
public:
void pushData(info * data) {
this->infoVector.push_back(&data);
}
};
int main(){
info * testData = new info(123, "nice");
db database;
database.pushData(testData);
return 0;
}
I am creating a object of info class. The object contains one int and one string variables. Then I am creating db object and I am passing there a testData object.
I got error message while building project.
main.cpp: In member function ‘void db::pushData(info*)’:
main.cpp:23:44: error: no matching function for call to ‘std::vector<info>::push_back(info*&)’
this->infoVector.push_back(data);
^
In file included from /usr/include/c++/5/vector:64:0,
from main.cpp:2:
/usr/include/c++/5/bits/stl_vector.h:913:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = info; _Alloc = std::allocator<info>; std::vector<_Tp, _Alloc>::value_type = info]
push_back(const value_type& __x)
^
/usr/include/c++/5/bits/stl_vector.h:913:7: note: no known conversion for argument 1 from ‘info*’ to ‘const value_type& {aka const info&}’
What am I doing wrong?
It looks like you are trying to pass the address of an info * type to vector<info>::push_back, which only accepts types of const info & or info &&. Try using the dereference operator * instead of the address-of operator & when you call push_back:
this->infoVector.push_back(*data);
This isn't a great way to use pointers, however, and could lead to memory leakage or segfaults if data is removed from the vector or if it is deleted. It is better for the vector to own its members, so you might consider doing this instead:
class db {
private:
vector<info> infoVector;
public:
void pushData(info data) { // note: not a pointer
this->infoVector.push_back(data); // note: not address-of
}
};
int main(){
info testData(123, "nice"); // note: not a pointer
db database;
database.pushData(testData);
return 0;
}
Otherwise, if you really want infoVector to contain pointers, declare it as:
std::vector<info*> infoVector;
Then remove the address-to operator.
P.S., avoid using namespace std whenever possible!
You have vector<info> and you want to put info *, try to do:
int main(){
info testData(123, "nice");
db database;
database.pushData(testData);
return 0;
}
I have a Load-Method which builds my unique_ptr (will be more than one later on) and a method to add these unique_ptr to my unordered map. But the code does not compile and I guess it has something to do with scoping...
Here is the code:
#include <unordered_map>
#include <memory>
class MyClass
{
public:
std::string Name;
};
using Map = std::unordered_map<std::string,std::unique_ptr<MyClass>>;
class MyContainer
{
private:
Map myMap;
void AddItem(std::unique_ptr<MyClass> item)
{
myMap.emplace("test", item);
}
public:
void LoadItems()
{
//Read a file ... do something before etc..
std::unique_ptr<MyClass> someItem(new MyClass);
someItem->Name = "FooBar";
AddItem(someItem);
}
};
This is one of the g++ error messages:
error: use of deleted function 'std::unique_ptr<_Tp,
_Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = MyClass; _Dp = std::default_delete]'
What is the best way to get this working? I tried changing the signature of the AddItem-method like so:
void AddItem(std::unique_ptr<MyClass>& item) //takes a reference now...
This leads to a real cryptic error message:
In instantiation of 'constexpr std::pair<_T1, _T2>::pair(_U1&&, const
_T2&) [with _U1 = const char (&)[5]; = void; _T1 = const std::basic_string; _T2 = std::unique_ptr]': e:\devtools\winbuilds\include\c++\4.8.3\bits\hashtable_policy.h:177:55:
required from 'std::__detail::_ ...
I suggest trying this piece of code on the fly here, to see the error messages:
http://cpp.sh/
You cannot copy a unique_ptr, because then it will not be unique. You have to move it - AddItem(std::move(someItem)); and myMap.emplace("test", std::move(item));.
You are trying to copy unique_ptr which is not allowed (that constructor is deleted as gcc says in the error). Instead of that you can try with std::move:
#include <unordered_map>
#include <memory>
#include <utility>
class MyClass
{
public:
std::string Name;
};
using Map = std::unordered_map<std::string,std::unique_ptr<MyClass>>;
class MyContainer
{
private:
Map myMap;
void AddItem(std::unique_ptr<MyClass> item)
{
myMap.emplace("test", std::move(item));
}
public:
void LoadItems()
{
//Read a file ... do something before etc..
std::unique_ptr<MyClass> someItem(new MyClass);
someItem->Name = "FooBar";
AddItem(std::move(someItem));
}
};
Be aware, do not use the moved object afterwards.
You can consider to use shared_ptr instead.
Although there is at least one similar question, I still ask mine since that one hasn't got solved and seems more complicated. I'm trying to simplify mine.
I have a .cpp file that uses .h as below, and compiling these sheds error as follows. Any idea is appreciated. Note that codes are simplified in order to minimally show the problematic parts only.
FC_boost_prove.h:
#ifndef FC_H
#define FC_H
#include <vector>
#include "iostream"
#include "boost/signal.hpp"
#include "boost/bind.hpp"
#include <boost/random.hpp>
typedef boost::signal0<void()> PreUpdateSignal;
typedef PreUpdateSignal::slot_function_type PreUpdateSlot;
typedef boost::signal0<void()> PostUpdateSignal;
typedef PostUpdateSignal::slot_function_type PostUpdateSlot;
class FC {
public:
FC(uint width, uint height) {
std::cout << "In constructor." << std::endl;
}
~FC() {
//Do ...
}
void connectPreUpdate(PreUpdateSlot s) {
preUpdateSignal_.connect(s);
}
void connectPostUpdate(PostUpdateSlot s) {
postUpdateSignal_.connect(s);
}
protected:
PreUpdateSignal preUpdateSignal_;
PostUpdateSignal postUpdateSignal_;
};
#endif
FC_boost_prove.cpp:
#include <iostream>
#include <string>
#include "FC_boost_prove.h"
int main() {
std::cout << "test." << std::endl;
}
Compile error:
$ g++ FC_boost_prove.cpp
In file included from /usr/include/boost/signals/signal_template.hpp:22,
from /usr/include/boost/signals/signal0.hpp:24,
from /usr/include/boost/signal.hpp:19,
from FC_boost_prove.h:7,
from FC_boost_prove.cpp:3:
/usr/include/boost/last_value.hpp: In instantiation of ‘boost::last_value<void()>’:
/usr/include/boost/signals/signal_template.hpp:178: instantiated from ‘boost::signal0<void(), boost::last_value<void()>, int, std::less<int>, boost::function0<void()> >’
FC_boost_prove.h:12: instantiated from here
/usr/include/boost/last_value.hpp:22: error: function returning a function
In file included from /usr/include/boost/signals/signal0.hpp:24,
from /usr/include/boost/signal.hpp:19,
from FC_boost_prove.h:7,
from FC_boost_prove.cpp:3:
/usr/include/boost/signals/signal_template.hpp: In instantiation of ‘boost::signal0<void(), boost::last_value<void()>, int, std::less<int>, boost::function0<void()> >’:
FC_boost_prove.h:12: instantiated from here
/usr/include/boost/signals/signal_template.hpp:330: error: function returning a function
/usr/include/boost/signals/signal_template.hpp:370: error: function returning a function
In file included from /usr/include/boost/function/detail/maybe_include.hpp:13,
from /usr/include/boost/function/function0.hpp:11,
from /usr/include/boost/signals/signal_template.hpp:38,
from /usr/include/boost/signals/signal0.hpp:24,
from /usr/include/boost/signal.hpp:19,
from FC_boost_prove.h:7,
from FC_boost_prove.cpp:3:
/usr/include/boost/function/function_template.hpp: In instantiation of ‘boost::function0<void()>’:
FC_boost_prove.h:24: instantiated from here
/usr/include/boost/function/function_template.hpp:1006: error: function returning a function
/usr/include/boost/function/function_template.hpp: In instantiation of ‘boost::detail::function::basic_vtable0<void()>’:
/usr/include/boost/function/function_template.hpp:856: instantiated from ‘void boost::function0<R>::clear() [with R = void()]’
/usr/include/boost/function/function_template.hpp:752: instantiated from ‘boost::function0<R>::~function0() [with R = void()]’
/usr/include/boost/signals/slot.hpp:105: instantiated from here
/usr/include/boost/function/function_template.hpp:486: error: function returning a function
/usr/include/boost/function/function_template.hpp:643: error: function returning a function
Environment: Ubuntu 10.10, g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5
Why are you specifying boost::signal0<>? The signalN templates are for deficient compilers that can't properly parse function signatures.
Either use signal and specify the function signature, as recommended for modern compilers:
typedef boost::signal<void()> PreUpdateSignal;
typedef boost::signal<void()> PostUpdateSignal;
or use signalN and specify the return type (and every argument type) explicitly, as needed for deficient compilers:
typedef boost::signal0<void> PreUpdateSignal;
typedef boost::signal0<void> PostUpdateSignal;