Use of boost coroutine2 without lambdas - c++

I guess this is the first time I couldn't manage to find an already answered question in here, and I could really use some help if anyone have successfully used boost coroutine2 lib without lambdas.
My problem, sumarized:
class worker {
...
void import_data(boost::coroutines2::coroutine
<boost::variant<long, long long, double, std::string> >::push_type& sink) {
...
sink(stol(fieldbuffer));
...
sink(stod(fieldbuffer));
...
sink(fieldbuffer); //Fieldbuffer is a std::string
}
};
I intend to use this as a coroutine from inside another class, that has the task of putting each yielded value in its place, so I tried to instantiate an object:
worker _data_loader;
boost::coroutines2::coroutine<boost::variant<long, long long, double, string>>::pull_type _fieldloader
(boost::bind(&worker::import_data, &_data_loader));
but that wont compile:
/usr/include/boost/bind/mem_fn.hpp:342:23:
error: invalid use of non-static member function of type
‘void (worker::)(boost::coroutines2::detail::push_coroutine<boost::variant<long int, long long int, double, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&)’
Could someone shed any light in this problem?

This has nothing to do with Boost Coroutine.
It is just about bind with a member function. You forgot to expose the unbound parameter:
boost::bind(&worker::import_data, &_data_loader, _1)
Live On Coliru
#include <boost/coroutine2/all.hpp>
#include <boost/variant.hpp>
#include <boost/bind.hpp>
#include <string>
using V = boost::variant<long, long long, double, std::string>;
using Coro = boost::coroutines2::coroutine<V>;
class worker {
public:
void import_data(Coro::push_type &sink) {
sink(stol(fieldbuffer));
sink(stod(fieldbuffer));
sink(fieldbuffer); // Fieldbuffer is a std::string
}
std::string fieldbuffer = "+042.42";
};
#include <iostream>
int main()
{
worker _data_loader;
Coro::pull_type _fieldloader(boost::bind(&worker::import_data, &_data_loader, _1));
while (_fieldloader) {
std::cout << _fieldloader.get() << "\n";
_fieldloader();
}
}
Prints
42
42.42
+042.42

Related

Threadpool works with C code but fails to build in C++ project

I am a beginner with threads and am trying to write code to extract 20 tags from a file.
The number of files can run up to 7000, so I would like to make good use of a thread-pool.
I use Code::Blocks 20.3 and MinGW 17.1 on a Windows 10 Pro computer.
I have 'borrowed' the thread-pool code from: https://codereview.stackexchange.com/questions/221626/c17-thread-pool
I made a test that MinGW probably handles as C code, and that worked just fine.
My project involves multiple class files with dialog windows, and when I copied the working C code it fails to build. Unfortunately I do not understand how to convert the code from C to C++.
The test code I wrote is below.
The build messages are:
||=== Build: Debug in ThreadPool2 (compiler: GNU GCC Compiler) ===|
Threadpool.h||In instantiation of 'auto Thread_Pool::execute(F, Args&& ...) [with F = TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>); Args = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}]':|
TrackTags.cpp|43|required from here|
Threadpool.h|62|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
Threadpool.h|63|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
Threadpool.h|62|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
Threadpool.h|63|error: no type named 'type' in 'struct std::invoke_result<TrackTags::TagsStdStrings (TrackTags::*)(std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char>), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>'|
TrackTags.cpp||In member function 'void TrackTags::GetMultiStdTags()':|
TrackTags.cpp|43|error: invalid use of void expression|
||=== Build failed: 5 error(s), 2 warning(s) (0 minute(s), 0 second(s)) ===|
the lines with errors are:
TrackTags.cpp
[43] StdFutures.push_back(Pool.execute(GetStdTags, wsFile, wsCol));
Threadpool.h
[62] std::packaged_task<std::invoke_result_t<F, Args...>()> Task_PKG(std::bind(function, args...) );
[63] std::future<std::invoke_result_t<F, Args...>> Future = Task_PKG.get_future();
in Threadpool.h.
I tried:
[43] StdFutures.push_back(Pool.execute(std::mem_fn(TrackTags::GetStdTags), std::ref(wsFile), std::ref(wsCol)));
But this did not help.
I hope someone can help me make this work.
Thank you.
Ruud.
---TrackTags.h---
#ifndef TRACKTAGS_H
#define TRACKTAGS_H
#include "Threadpool.h"
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
#include <vector>
class TrackTags
{
public:
struct TagsStdStrings
{
bool OK;
std::string ThreadID;
std::string FileName;
std::string Collection;
};
public:
TrackTags();
virtual ~TrackTags();
TagsStdStrings GetStdTags(std::string wsFile, std::string wsCollection);
void GetMultiStdTags();
protected:
private:
};
#endif // TRACKTAGS_H
---TrackTags.cpp---
#include "TrackTags.h"
#define _UNICODE
TrackTags::TrackTags()
{
//ctor
}
TrackTags::~TrackTags()
{
//dtor
}
TrackTags::TagsStdStrings TrackTags::GetStdTags(std::string wsFile, std::string wsCollection)
{
TagsStdStrings TagLine;
TagLine.FileName = wsFile;
TagLine.Collection = wsCollection;
TagLine.OK = true;
// Add thread-ID to the structure
auto tid = std::this_thread::get_id();
std::stringstream ssID;
ssID << tid;
std::string sID{ssID.str()};
TagLine.ThreadID = sID;
return TagLine;
}
void TrackTags::GetMultiStdTags()
{
Thread_Pool Pool(1);
std::vector<std::future<TagsStdStrings>> StdFutures;
std::string wsFile{"FileTest"};
std::string wsCol{"ColTest"};
StdFutures.push_back(Pool.execute(GetStdTags, wsFile, wsCol));
for (auto &Fut : StdFutures)
{
TagsStdStrings TSS;
TSS = Fut.get();
if (TSS.OK)
{ std::cout << TSS.ThreadID << "--" << TSS.FileName << "--" << TSS.Collection << std::endl; }
else
{ std::cout << "Empty Tag structure\n"; }
}
}
---Threadpool.h---
#pragma once
#include <condition_variable>
#include <functional> //bind
#include <future> //packaged_task
#include <mutex>
#include <queue>
#include <thread>
#include <type_traits> //invoke_result
#include <vector>
class Thread_Pool
{
public:
Thread_Pool(size_t Thread_Count);
~Thread_Pool();
Thread_Pool(const Thread_Pool &) = delete;
Thread_Pool &operator=(const Thread_Pool &) = delete;
template <typename F, typename ...Args>
auto execute(F, Args&&...);
private:
class Task_Container_Base
{
public:
virtual ~Task_Container_Base() {};
virtual void operator()() = 0;
};
template <typename F>
class Task_Container : public Task_Container_Base
{
public:
Task_Container(F &&Fnc) : f(std::forward<F>(Fnc)) {}
void operator()() override { f(); }
private:
F f;
};
template <typename Func>
static std::unique_ptr<Task_Container_Base> Allocate_Task_Container(Func &&f)
{
return std::unique_ptr<Task_Container_Base>(new Task_Container<Func>(std::forward<Func>(f))
);
}
std::vector<std::thread> Threads;
std::queue<std::unique_ptr<Task_Container_Base>> Tasks;
std::mutex Task_Mutex;
std::condition_variable Task_CV;
bool Stop_Threads = false;
};
template <typename F, typename ...Args>
auto Thread_Pool::execute(F function, Args &&...args)
{
std::unique_lock<std::mutex> Queue_Lock(Task_Mutex, std::defer_lock);
std::packaged_task<std::invoke_result_t<F, Args...>()> Task_PKG(std::bind(function, args...) );
std::future<std::invoke_result_t<F, Args...>> Future = Task_PKG.get_future();
Queue_Lock.lock();
Tasks.emplace(Allocate_Task_Container( [Task(std::move(Task_PKG))]() mutable { Task(); }) );
Queue_Lock.unlock();
Task_CV.notify_one();
return Future;
}
---Threadpool.cpp---
#include "Threadpool.h"
Thread_Pool::Thread_Pool(size_t Thread_Count)
{
for (size_t i = 0; i < Thread_Count; ++i)
{
Threads.emplace_back( std::thread( [&]()
{
std::unique_lock<std::mutex> Queue_Lock(Task_Mutex, std::defer_lock);
while (true)
{
Queue_Lock.lock();
Task_CV.wait( Queue_Lock, [&]() -> bool { return !Tasks.empty() || Stop_Threads; } );
if (Stop_Threads && Tasks.empty()) return;
auto Temp_Task = std::move(Tasks.front());
Tasks.pop();
Queue_Lock.unlock();
(*Temp_Task)();
}
} ) );
}
}
Thread_Pool::~Thread_Pool()
{
Stop_Threads = true;
Task_CV.notify_all();
for (std::thread &Thread : Threads)
{
Thread.join();
}
}
GetStdTags is a non-static member function. You have access to this - the pointer to the object you're calling it on - inside it. Therefore when you call it, you need to specify the object which the member function should be working on.
Pool.execute(GetStdTags, wsFile, wsCol)
Here you only specify the two formal arguments, but not the object for the member function. Passing that along would look like this:
TrackTags one_object; // < yes, ONE, shared between the threads!
// if you don't want to share it between threads,
// you need to create multiple objects (and keep them alive)
Pool.execute(&TrackTags::GetStdTags, &one_object, wsFile, wsCol)
// ^ pointer to member ^ pointer
// function to object,
// "this" inside the
// member function
More information about std::bind and member functions.
However, since your class (TrackTags) doesn't have any data members and the member function GetStdTags doesn't need access to any object of type TrackTags, you can make it a static member function (or even a free function, really) and get by without a TrackTags object.
Thank you Daniel.
The test project seemed to work, so I started on the "real" thing.
It is building without errors, but not working as planned.
I tested with 4 threads and 4 files and ran it twice.
Result below: What did I miss?
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\01 Adam Baldych - Bridges.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\02 Adam Baldych - Polesie.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\03 Adam Baldych - Mosaic.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\04 Adam Baldych - Riese.flac
6--Riese--Col Test
7--Riese--Col Test
8--Riese--Col Test
9--Riese--Col Test
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\01 Adam Baldych - Bridges.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\02 Adam Baldych - Polesie.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\03 Adam Baldych - Mosaic.flac
B:\Music\FLAC_Unlisted\Adam Baldych\Bridges\04 Adam Baldych - Riese.flac
First run, completes, but with wrong results, and the second run immediately after the first completed hangs.
This is the function called:
TrackTags::TagsStruct TrackTags::GetTags(wxString wsFile, wxString wsCollection)
{
// create Tag variable structure
struct TagsStruct TagLine;
.
.
return TagLine
}
It loads a DLL and extracts the required tags from a file to return it in a structure with the Thread-ID as first item (temporary to check how the code runs).
The calling function is below:
void TrackTags::GetMultiStdTags()
{
wxString wsCol{"Col Test"};
std::vector<wxString> wsTracks
{
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\01 Adam Baldych - Bridges.flac",
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\02 Adam Baldych - Polesie.flac",
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\03 Adam Baldych - Mosaic.flac",
"B:\\Music\\FLAC_Unlisted\\Adam Baldych\\Bridges\\04 Adam Baldych - Riese.flac"
};
TrackTags one_object;
Thread_Pool Pool(4);
std::vector<std::future<TagsStruct>> StdFutures;
for (auto &tr : wsTracks)
{
std::cout << tr << std::endl;
StdFutures.push_back(Pool.execute(&TrackTags::GetTags, &one_object, tr, wsCol));
}
for (auto &Fut : StdFutures)
{
TagsStruct TSS;
TSS = Fut.get();
if (TSS.OK)
{ std::cout << TSS.ThreadID << "--" << TSS.TrackTitle << "--" << TSS.Collection << std::endl; }
else
{ std::cout << "Empty Tag structure found\n"; }
}
}

C++ - Vector of function pointers inside class

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); });

boost::any_range with optimization level -O2 causes crash

What is the problem with this code:
#include <iostream>
#include <vector>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/any_range.hpp>
using namespace boost::adaptors;
using Range =
boost::any_range<
int,
boost::forward_traversal_tag,
int,
std::ptrdiff_t>;
void magic(const Range &) {}
int main()
{
std::vector<int> xs{0, 1, 2};
auto ys = xs | transformed([](auto x) { return x; });
const Range zs = ys;
std::vector<int> us{boost::begin(zs), boost::end(zs)};
magic(us);
return 0;
}
Complie:
c++ -g -std=c++14 -O2 main.cpp
Run and get segfault.
But when I compile with lower optimization level, then everything is ok.
gdb output:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004011a5 in boost::range_detail::any_iterator<int, boost::iterators::forward_traversal_tag, int, long, boost::any_iterator_buffer<64ul> >::dereference (this=<optimized out>) at /usr/include/boost/range/detail/any_iterator.hpp:512
512 return m_impl->dereference();
Is this boost::any_range bug, or I misuse the library?
Program also crashes if I compile it this way:
c++ -g -std=c++14 -O1 -fisolate-erroneous-paths-dereference main.cpp
The program below crashes too, if I compile it with options -O1 -fisolate-erroneous-paths-dereference:
#include <iostream>
#include <vector>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/any_range.hpp>
using namespace boost::adaptors;
using Range =
boost::any_range<
int,
boost::forward_traversal_tag,
int &,
std::ptrdiff_t>;
void magic(const Range &xs) {
for (auto x: xs) { std::cout << xs; }
}
int main()
{
std::vector<int> xs{0, 1, 2};
auto ys = xs | transformed([](auto x) { return x; });
magic(ys);
return 0;
}
This is boost bug 10493, related to 10360, which was introduced in 1.56 (2014-08) and was only finally fixed in 1.74 (2020-08) via fix PR #94
Until 1.74, the problem is that instead of just using your reference type, it wraps it in mutable_reference_type_generator, which prevents you from being able to return a temporary. That is, when you write:
using Range =
boost::any_range<
int,
boost::forward_traversal_tag,
int,
std::ptrdiff_t>;
You're explicitly specifying your reference type to be int, not int&, because your range is basically an input range. But the boost internals are changing it to int& anyway, so you dangle. When you write const int intsead of int, the type trait doesn't add the reference, so you actually do end up with const int.
Actually when I was typing the title for my question, this question was offered as possible answer.
As suggested in the answer for the question, I replaced int with const int and it worked:
using Range =
boost::any_range<
int,
boost::forward_traversal_tag,
const int,
std::ptrdiff_t>;
I decided to publish the question because the quoted question is not marked as answered.

Boost karma: how does this implicit call to transform_attribute work? (or doesn't?)

I have the following piece of code that seems to work fine (I based the semantic actions on reuse parsed variable with boost karma).
#include <iostream>
#include <iterator>
#include <memory>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/sequence.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/support_attributes.hpp>
#include <boost/spirit/include/support_adapt_adt_attributes.hpp>
using namespace boost::spirit;
struct DataElement
{
DataElement(const std::string& s) : str_(s) {}
const std::string& str() const { return str_; }
std::string& str() { return str_; }
std::string str_;
};
using Data = std::vector<std::shared_ptr<const DataElement>>;
namespace boost {
namespace spirit {
namespace traits {
template<>
struct transform_attribute<std::shared_ptr<const DataElement> const, const DataElement&, karma::domain>
{
using type = const DataElement&;
static type pre(const std::shared_ptr<const DataElement>& val) { return *val; }
};
}
}
}
BOOST_FUSION_ADAPT_ADT(
DataElement,
(std::string&, const std::string&, obj.str(), obj.str())
);
template<typename Iterator>
struct TheGrammar: public karma::grammar<Iterator, Data()>
{
TheGrammar(): karma::grammar<Iterator, Data()>(start)
{
start %= -(elt % karma::eol);
elt %=
karma::lit("'some prefix'")
<< karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)]
<< karma::lit("'some infix 1'")
<< karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)]
<< karma::lit("'some infix 2'")
<< karma::string [karma::_1 = boost::phoenix::at_c<0>(karma::_val)]
<< karma::lit("'some suffix'")
;
}
karma::rule<Iterator, Data()> start;
karma::rule<Iterator, const DataElement&()> elt;
};
int main(void)
{
Data vec = {
std::make_shared<DataElement>("one"),
std::make_shared<DataElement>("two"),
std::make_shared<DataElement>("three"),
std::make_shared<DataElement>("four"),
std::make_shared<DataElement>("five"),
std::make_shared<DataElement>("six"),
std::make_shared<DataElement>("seven"),
std::make_shared<DataElement>("eight"),
};
using iterator_type = std::ostream_iterator<char>;
iterator_type out(std::cout);
TheGrammar<iterator_type> grammar;
return karma::generate(out, grammar, vec);
}
I would like to understand a couple of things:
Why don't I need to use karma::attr_cast anywhere? My start rule is a vector of std::shared_ptr whereas the elt rule works on the actual object const reference. I originally tried attr_cast but got nowhere, and sort of tried this version only halfheartedly just in case it worked, and it worked...
Why does it still compile if I comment out my custom transform_attribute altogether? Is there some default std::shared_ptr<T> -> T& transform_attribute provided? I couldn't find much, but maybe I'm not looking int the right place?
If I comment out my custom transform_attribute, as mentioned above, the code still compiled, but there's clearly some memory corruption at runtime. The karma::string generate garbage. In a way, I can understand that something funny must be happening since I don't even tell karma how to get from my shared_ptr to the objects. Is the fact that it compiles the actual error/bug?
Thanks a lot for your time and help!
each rule has an implicit attr_cast to the declared attribute type
Somehwere along the way Spirit's type compatibility rules go haywire. All I've seen is it has to do with the fact that the string type is a container. Somewhere along the way it "copy-constructs" a std::string that appears to have length 97332352. Unsurprisingly that is itself wrong and happens to trigger UB because the ranges that end up being passed to memset overlap:
Source and destination overlap in memcpy(0x60c1040, 0x5cd2c90, 97332352)
at 0x4C30573: memcpy##GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x401B26: copy (char_traits.h:290)
by 0x401B26: _S_copy (basic_string.h:299)
by 0x401B26: _S_copy_chars (basic_string.h:342)
by 0x401B26: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) [clone .isra.53] (basic_string.tcc:229)
by 0x402442: _M_construct_aux<char*> (basic_string.h:195)
by 0x402442: _M_construct<char*> (basic_string.h:214)
by 0x402442: basic_string (basic_string.h:401)
by 0x402442: call<const boost::spirit::unused_type> (extract_from.hpp:172)
by 0x402442: call<const boost::spirit::unused_type> (extract_from.hpp:184)
by 0x402442: extract_from<std::__cxx11::basic_string<char>, boost::fusion::extension::adt_attribute_proxy<DataElement, 0, true>, const boost::spirit::unused_type> (extract_from.hpp:217)
by 0x402442: extract_from<std::__cxx11::basic_string<char>, boost::fusion::extension::adt_attribute_proxy<DataElement, 0, true>, const boost::spirit::unused_type> (extract_from.hpp:237)
by 0x402442: pre (attributes.hpp:23)
Yes, that's a QoI issue.
The problem often is with c++'s implicit conversions. Pointer types have many unexpected conversions. Shared pointers do have their contextual conversion to bool.
More notes:
Your fusion adaptation seemed flawed: val was not being used in the setter
BOOST_FUSION_ADAPT_ADT(DataElement, (std::string &, const std::string &, obj.str(), obj.str() = val))
You're doing many things I've learned to avoid.
I prefer to have semantic-action-less rules: Boost Spirit: "Semantic actions are evil"?
I don't do shared-pointers in Spirit grammars/generators How can I use polymorphic attributes with boost::spirit::qi parsers? (arguably, in a generator setting it's less of a problem!)
I don't do ADT adaptation (it's too easy to get bitten with UB) Error when adapting a class with BOOST_FUSION_ADAPT_ADT

error: function returning a function

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;