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");
}
Related
I've designed a class with two overloaded functions taking Eigen data structures of different sizes.
The code compiles as long as I'm passing lvalues but if I pass an rvalue I get a compiler error ambiguity because both return the same ConstantReturnType.
Here is a MWE:
#include <iostream>
#include <Eigen/Geometry>
using namespace std;
using namespace Eigen;
class MyOverloadAmbiguity {
public:
void ambiguousOverload(const Eigen::Vector3d& v) {
std::cout << "I'm taking a Vector3d\n";
}
void ambiguousOverload(const Eigen::Vector4d& v){
std::cout << "I'm taking a Vector4d\n";
}
};
int main()
{
MyOverloadAmbiguity moa;
Eigen::Vector3d v3;
moa.ambiguousOverload(v3); // <--- this works
moa.ambiguousOverload(Eigen::Vector4d::Zero()); // <--- this doesn't
return 0;
}
main.cpp:26: error: call of overloaded ‘ambiguousOverload(const ConstantReturnType)’ is ambiguous
26 | moa.ambiguousOverload(Eigen::Vector4d::Zero());
| ^
main.cpp:10:8: note: candidate: ‘void MyOverloadAmbiguity::ambiguousOverload(const Vector3d&)’
10 | void ambiguousOverload(const Eigen::Vector3d& v) {
| ^~~~~~~~~~~~~~~~~
main.cpp:13:8: note: candidate: ‘void MyOverloadAmbiguity::ambiguousOverload(const Vector4d&)’
13 | void ambiguousOverload(const Eigen::Vector4d& v){
| ^~~~~~~~~~~~~~~~~
Is there a way to avoid this without explicitly changing the function names or add extra arguments just to avoid the ambiguity?
Your example does not work because the return type of Zero() is not a matrix, but an Eigen expression.
Thus, one way of achieving what you want with minimal changes is to use explicit matrix evaluation:
moa.ambiguousOverload(Eigen::Vector4d::Zero().eval());
You may also want to consider writing functions taking Eigen expressions as parameters (rather than explicit matrices), as an alternative solution.
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.
I am making my own programming language. I made classes (like 'string' or 'int) that derive from the object class. I am making standard types like string and int so I have a base I can work off (expand my language with itself if that makes sense). Each standard type has a unordered_map of functions. I would love to hear a way to fix this/another approach.
When I run the program, I get this error that I don't understand:
C2664: 'std::pair<const _Kty,_Ty>::pair(std::pair<const _Kty,_Ty> &&)': cannot convert argument 2 from '_Ty' to 'const _Ty2 &'
It's referring to line 62. Where the error comes from:
c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\xmemory0 line:881
The code from xmemory0:
template<class _Objty,
class... _Types>
static void construct(_Alloc&, _Objty * const _Ptr, _Types&&... _Args)
{ // construct _Objty(_Types...) at _Ptr
::new (const_cast<void *>(static_cast<const volatile void *>(_Ptr)))
_Objty(_STD forward<_Types>(_Args)...);
}
My code:
#include <iostream>
#include <unordered_map>
#include <string>
#include <functional>
struct Object;
typedef std::unordered_map<std::string, std::function<Object*(std::string*)>> stdtypefunc_map;
struct Object
{
};
struct StdType : public Object
{
stdtypefunc_map functions;
};
struct stringtype : public StdType
{
stringtype()
{
functions.emplace("GetValue", &stringtype::GetValue);
}
Object* GetValue(std::string args[])
{
std::cout << "GetValue()" << std::endl;
}
};
int main()
{
stringtype s;
return 0;
}
In your code, line 62 is this statement:
functions.emplace("GetValue", &stringtype::GetValue);
functions is an std::unordered_map whose key_type is std::string and mapped_type is std::function<Object*(std::string*)>.
emplace() constructs a new std::unordered_map::value_type in the map, passing the values you specify to the value_type's constructor. In this case, that value_type is a std::pair<const std::string, std::function<Object*(std::string*)>>, and you are passing in 2 values to constructor the std::pair with.
The error message you are seeing is basically saying that the compiler can't convert &stringtype::GetValue to std::function<Object*(std::string*)>. For example, here is a simplified example that reproduces the same failure, and GCC gives a VERY DETAILED error message explaining why it failed (which is too large to post here, so I'll post only the relevant pieces):
https://ideone.com/qVLkQd
#include <iostream>
#include <unordered_map>
#include <string>
#include <functional>
struct Object;
typedef std::unordered_map<std::string, std::function<Object*(std::string*)>> stdtypefunc_map;
struct Object
{
};
struct StdType : public Object
{
stdtypefunc_map functions;
};
struct stringtype : public StdType
{
stringtype()
{
functions.emplace("GetValue", &stringtype::GetValue);
}
Object* GetValue(std::string args[])
{
std::cout << "GetValue()" << std::endl;
}
};
int main()
{
stringtype s;
return 0;
}
/usr/include/c++/6/ext/new_allocator.h:120:4: error: no matching function for call to ‘std::pair<const std::__cxx11::basic_string<char>, std::function<Object*(std::__cxx11::basic_string<char>*)> >::pair(const char [9], Object* (stringtype::*)(std::__cxx11::basic_string<char>*))’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
/usr/include/c++/6/ext/new_allocator.h:120:4: note: cannot convert ‘std::forward<Object* (stringtype::*)(std::__cxx11::basic_string<char>*)>((* & __args#1))’ (type ‘Object* (stringtype::*)(std::__cxx11::basic_string<char>*)’) to type ‘const std::function<Object*(std::__cxx11::basic_string<char>*)>&’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
Which makes sense. You can't store a pointer-to-member-method for a non-static method into a std::function unless you take into account that it will need an object instance to call the method on. Such as by using std::bind() to bind an object instance with the pointer-to-member-method:
using std::placeholders::_1;
functions.emplace("GetValue", std::bind(&stringtype::GetValue, this, _1));
Or, by using a lambda to capture the object:
functions.emplace("GetValue", [this](std::string *args){ return this->GetValue(args); });
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.