I'd like a variant contain copies of objects of its type. Somehow it is not working:
struct value
{
};
class json;
using json = ::boost::variant<
::std::vector<::std::unique_ptr<json> >,
::std::unordered_map<::std::string, ::std::unique_ptr<json> >,
value
>;
json.hpp:116:2: error: conflicting declaration 'using json = '
>;
^
json.hpp:110:7: error: 'class json' has a previous declaration as 'class json'
class json;
I know of 2 workarounds already: ::std::unique_ptr<void>, with a custom deleter, as well as the possibility of using ::boost::any instead of the variant, but are these the only ways? The problem with ::boost::any is that I need to enable RTTI for it to work.
What about:
struct json : ::boost::variant<
::std::vector<::std::unique_ptr<json> >,
::std::unordered_map<::std::string, ::std::unique_ptr<json> >,
value
>
{
using variant::variant;
template <typename U>
json& operator=(U&& u)
{
variant::operator=(::std::forward<U>(u));
return *this;
}
};
That would be the solution, except it doesn't work for me with g++ (constructing json out of vector fails because of ambiguous constructor call). Construction from a const reference to such a vector works, but not not from a non-const reference. I have no idea why. In addition, unique_ptr doesn't work with boost::variant for me because it's uncopyable (shared_ptr does work).
Related
Sorry for the generic title, but I'm unable to focus the problem.
I have a templatized class method that accept an argument pack and provides a new type in return, to hide the details of the implementation. More specifically, the class handles SQLite queries, and the method calls sqlite3_prepare() to prepare the statement before executing the query.
class Table {
...
template <typename ...Ts>
class PreparedStatement { ... };
template <typename ...Ts>
PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
// do something
return PreparedStatement<Ts...> ( ... );
}
That works well with "normal" types, but the problem occurs when the arguments are declared const:
const Field<int> fld = createField<int>("name");
...
PreparedStatement<decltype(fld)> s = prepare(make_tuple(fld));
The error is the following:
no match for 'operator =' (operand types are PreparedStatenent<const Field<int>> and PreparedStatement<Field<int>>
I suspect the issue is in my declaration of the function, is there a way to fix this issue and make the function more "elegant" ?
NOTE: I know I can fix the issue by manually declare the s variable, but my doubts are on how the method was implemented.
As Many Asked, here's an example:
#include <tuple>
template <typename T>
struct Field {
};
class Table {
public:
template <typename ...Ts>
class PreparedStatement {
public:
PreparedStatement() {};
};
template <typename ...Ts>
PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
// do something
return PreparedStatement<Ts...> ( );
}
};
int main()
{
Field<int> fld;
Table t;
Table::PreparedStatement<decltype(fld)> p;
p = t.prepare(std::make_tuple(fld));
// here comes the problem
const Field<int> f2;
Table::PreparedStatement<decltype(f2)> p2;
p2 = t.prepare(std::make_tuple(f2));
return 0;
}
and here's the compiler output
main.cpp: In function 'int main()': main.cpp:35:39: error: no match
for 'operator=' (operand types are 'Table::PreparedStatement >' and 'Table::PreparedStatement >')
p2 = t.prepare(std::make_tuple(f2));
^ main.cpp:10:10: note: candidate: constexpr Table::PreparedStatement >&
Table::PreparedStatement >::operator=(const
Table::PreparedStatement >&)
class PreparedStatement {
^~~~~~~~~~~~~~~~~ main.cpp:10:10: note: no known conversion for argument 1 from 'Table::PreparedStatement >'
to 'const Table::PreparedStatement >&'
main.cpp:10:10: note: candidate: constexpr
Table::PreparedStatement >&
Table::PreparedStatement
::operator=(Table::PreparedStatement >&&) main.cpp:10:10: note: no known conversion for argument 1 from
'Table::PreparedStatement >' to
'Table::PreparedStatement >&&'
UPDATE
As many noted, I could use auto to deduce the type, but in some condition auto cannot practically be used. One is, for example, if I need to declare the statement in the Class Context.
So suppose auto is forbidden for some reason. Isn't any other solution available? See the updated code above.
cppreference.com for make_tuple tells us:
template< class... Types >
tuple<VTypes...> make_tuple( Types&&... args );
For each Ti in Types..., the corresponding type Vi in Vtypes... is
std::decay<Ti>::type unless application of std::decay results in
std::reference_wrapper<X> for some type X, in which case the deduced
type is X&.
While std::decay, among other things, removes cv-qualifiers. So your type will be no PreparedStatement<const Field<int>>, but PreparedStatement<Field<int>>.
You can use auto, as manni66 proposed, to avoid such problems.
auto s = prepare(make_tuple(fld));
I could use auto to deduce the type, but in some condition auto cannot practically be used. One is, for example, if I need to declare the statement in the Class Context. So suppose auto is forbidden for some reason. Isn't any other solution available? See the updated code above.
Instead of auto, you can use a decltype expression that take in count the value returned by prepare.
I mean... instead of
Table::PreparedStatement<decltype(f2)> p2;
you can try with
decltype(t.prepare(std::make_tuple(f2))) p2;
or
decltype(std::declval<Table>().prepare(
std::make_tuple(std::declval<Field<int>>()))) p2;
I suppose you can use a similar decltype() also to declare members of your classes.
I trying to fix pretty hard program to me I got from gamedev book. I think it's crashed because an author used Windows and I use Linux (g++). In short I have couple of classes to perform Application State's logic, and I have map of maps to hold states with its callbacks:
enum class StateType {
Intro = 1, MainMenu, Game, Paused, GameOver, Credits
};
using Bindings = std::unordered_map<std::string, Binding*>;
using CallbackContainer = std::unordered_map<std::string, std::function<void(EventDetails*)>>;
using Callbacks = std::unordered_map<StateType, CallbackContainer>;
class EventManager {
public:
...
template<class T>
bool AddCallback(StateType l_state, const std::string& l_name,
void(T::*l_func)(EventDetails*), T* l_instance) {
auto itr = m_callbacks.emplace(l_state, CallbackContainer()).first;
auto temp = std::bind(l_func, l_instance, std::placeholders::_1);
return itr->second.emplace(l_name, temp).second;
}
private:
Callbacks m_callbacks;
I'm not sure what parts of my code to include here. Anyway I get a terrible stack trace:
/usr/include/c++/5/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::__is_noexcept_hash<StateType, std::hash<StateType> >’:
/usr/include/c++/5/type_traits:137:12: required from ‘struct std::__and_<std::__is_fast_hash<std::hash<StateType> >, std::__detail::__is_noexcept_hash<StateType, std::hash<StateType> > >’
/usr/include/c++/5/type_traits:148:38: required from ‘struct std::__not_<std::__and_<std::__is_fast_hash<std::hash<StateType> >, std::__detail::__is_noexcept_hash<StateType, std::hash<StateType> > > >’
/usr/include/c++/5/bits/unordered_map.h:100:66: required from ‘class std::unordered_map<StateType, std::function<BaseState*()> >’
/home/xxx/Projects/mushrooom/BaseState.h:48:28: required from here
/usr/include/c++/5/bits/hashtable_policy.h:85:34: error: no match for call to ‘(const std::hash<StateType>) (const StateType&)’
noexcept(declval<const _Hash&>()(declval<const _Key&>()))>
...
/usr/include/c++/5/bits/unordered_map.h:649:7: error: ‘value’ is not a member of ‘std::__not_<std::__and_<std::__is_fast_hash<std::hash<StateType> >, std::__detail::__is_noexcept_hash<StateType, std::hash<StateType> > > >’
equal_range(const key_type& __x) const
...
/home/xxx/Projects/mushrooom/EventManager.h: In member function ‘bool EventManager::AddCallback(StateType, const string&, void (T::*)(EventDetails*), T*)’:
/home/xxx/Projects/mushrooom/EventManager.h:93:32: error: ‘using Callbacks = class std::unordered_map<StateType, std::unordered_map<std::basic_string<char>, std::function<void(EventDetails*)> > > {aka class std::unordered_map<StateType, std::unordered_map<std::basic_string<char>, std::function<void(EventDetails*)> > >}’ has no member named ‘emplace’
auto itr = m_callbacks.emplace(l_state, CallbackContainer()).first;
Seems like Callbacks has no member emplace, but it's std::unordered_map and it has such method.
g++-5, linux
It has nothing to do with emplace - it is the missing hash function!
You are using an std::unordered_map, which is in other words a hash map. If you want to use an object as a key, this object must provide a function by which a hash value can be calculated.
You now have two options:
provide a template specialisation of std::hash for your class or pass an own class as third (hasher) template parameter to std::unordered_map
use std::map instead - this is a tree-map not requiring a hash function.
Background
I have been writing a StateMachine whose transition table is loaded at runtime. The action to take upon each transition is stored as a string. The string is converted to a std::function object that points to a member function of the state machine class. When an event occurs, and results in a transition, that function is invoked.
Problem
I have successfully used this strategy before to decide which function is called at run time. Unfortunately, I've been running into the following error:
error: return type 'XStMachine::TrFunc {aka class std::function<void (XStMachine::*)(const EventData&)>}' is incomplete
Or
invalid use of incomplete type
Steps Taken
I consulted Google and Stackoverflow. I got a number of ideas including taking the definition out of the place where the type is incomplete. Unfortunately, I couldn't get it to work successfully.
I tried using a raw pointer instead of a unique_ptr and found that things worked magically.
I ended up reading a little on the difference between how shared_ptr and unique_ptr handle incomplete types. I tried a shared_ptr, but that did not solve my issue either.
I tried creating a friend class to my state machine in the hope that by the time of the friend class' declaration, the type would be considered whole. I could not get this to work.
Finally, I created the following minimal example (Uncomment code to reproduce the error, please.) which demonstrates the problems I ran into: http://coliru.stacked-crooked.com/a/791092c7ca8fff24 and came to the experts! :)
Source Code
#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include <map>
#include <iomanip>
using namespace std;
struct EventData
{
unsigned int x;
};
class Friendly; // Required for compiling the code. Why?
class XStMachine
{
friend class Friendly;
unique_ptr<Friendly> fPtr; //-- Doesn't compile if Friendly is not fwd. declared
unsigned int y;
unsigned int z;
public:
typedef void(XStMachine::*TrFuncPtr)(EventData const&);
typedef std::function<TrFuncPtr> TrFunc;
private:
// map<string, TrFunc> fMap; //-- Doesn't compile because TrFunc is incomplete
// unique_ptr<map<string, TrFunc>> fMap; // Doesn't compile; incomplete type.
map<string, TrFunc> *fMap; // Compiles with incomplete type.
protected:
void tranFunc1(EventData const &d)
{
y = d.x;
}
void tranFunc2(EventData const &d)
{
z = d.x;
}
public:
XStMachine()
{
// Code to init fMap
}
// The code below doesn't compile. incomplete type.
TrFunc getTranFunc(std::string const &s)
{
return (*fMap)[s];
}
~XStMachine()
{
}
};
class Friendly
{
// unique_ptr<map<string, XStMachine::TrFunc> fMap; // Doesn't compile, the type is incomplete.
public:
Friendly()
{
// Code to allocate and init fMap
}
// Dosen't compile if defined here because the return type is incomplete.
//XStMachine::TrFunc& getTranFunc(std::string const&)
//{
// return (*fMap)[s];
//}
};
// The type is incomplete -> Will this work inside a separate cpp file?
//XStMachine::TrFunc& getTranFunc(std::string const &s)
//{
// Weird - Can't access protected members though we're friends. :/
/*
static map<string, XStMachine::TrFunc> fMap = {{"tranFunc1", function(&XStMachine::tranFunc1)},
{"tranFunc2", function(&XStMachine::tranFunc2)}
};
*/
//return fMap[s];
//}
int main() {
cout << "I need to understand incomplete types." << endl;
return 0;
}
Full Error Output from Coliru (gcc 6.3, C++ 14)
main.cpp: In member function 'XStMachine::TrFunc XStMachine::getTranFunc(const string&)':
main.cpp:48:3: error: return type 'XStMachine::TrFunc {aka class std::function<void (XStMachine::*)(const EventData&)>}' is incomplete
{
^
In file included from /usr/local/include/c++/6.3.0/bits/stl_algobase.h:64:0,
from /usr/local/include/c++/6.3.0/bits/char_traits.h:39,
from /usr/local/include/c++/6.3.0/ios:40,
from /usr/local/include/c++/6.3.0/ostream:38,
from /usr/local/include/c++/6.3.0/iostream:39,
from main.cpp:1:
/usr/local/include/c++/6.3.0/bits/stl_pair.h: In instantiation of 'struct std::pair<const std::__cxx11::basic_string<char>, std::function<void (XStMachine::*)(const EventData&)> >':
/usr/local/include/c++/6.3.0/bits/stl_map.h:481:10: required from 'std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = std::__cxx11::basic_string<char>; _Tp = std::function<void (XStMachine::*)(const EventData&)>; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, std::function<void (XStMachine::*)(const EventData&)> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::function<void (XStMachine::*)(const EventData&)>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::__cxx11::basic_string<char>]'
main.cpp:49:23: required from here
/usr/local/include/c++/6.3.0/bits/stl_pair.h:196:11: error: 'std::pair<_T1, _T2>::second' has incomplete type
_T2 second; /// #c second is a copy of the second object
^~~~~~
In file included from main.cpp:3:0:
/usr/local/include/c++/6.3.0/functional:1526:11: note: declaration of 'class std::function<void (XStMachine::*)(const EventData&)>'
class function;
^~~~~~~~
Objectives
Primary: Understand what is going on in the example code and fix it.
Secondary: Gain a clear understanding of what an incomplete type is so that I can:
* Solve related problems in the future.
* Know if it is safe to override unique_ptr's default deleter with a deleter that calls the default.
My lack of understanding is really getting in my way here.
Related Questions
Even though Friendly is declared as a friend within XStMachine in the example code, it has to be forward declared earlier in the program as well. Why does this happen?
Even though Friendly is declared a friend, it cannot access protected member functions of XStMachine. For instance, &XStMachine::tranFunc1 is invalid. Why?
std::function takes only a regular function type as template argument. A pointer-to-member-function type doesn't work.
Below is what might be a typical definition of std::function in the standard library:
template< class >
class function; // intentionally undefined
template< class R, class... Args >
class function<R(Args...)> // actual definition
The template argument doesn't determine what kind of function this instantiation can store, but rather how this instantiation can be called.
Any instantiation attempt with a type that is not a regular function type will produce an incomplete type. Example:
std::function <int> incomplete;
In your code you may either:
store std::function<void(EventData const&)> in the map (use std::bind to construct these objects from a pointer-to-member-function and an object pointer); or
do away with std::function altogether and store pointers-to-member-function in the map directly.
I plan to use my own compare function with boost bimap. The issue i am trying to address is when i use boost bimap with a pointer, the comparison should not compare the two pointers but should compare the class which is pointed by the pointer.
I tried the following code. But it doesn't even compile. What am i doing wrong? Also is there a simpler way to achieve less function that compares two objects and not two pointers pointers)
typedef std::set<int> ruleset;
template <class myclass>
bool comp_pointer(const myclass &lhs, const myclass &rhs)
{
return ((*lhs) < (*rhs));
}
typedef boost::bimap<set_of<ruleset *, comp_pointer<ruleset *> >, int> megarulebimap;
Error messages:
party1.cpp:104:64: error: type/value mismatch at argument 2 in template parameter list for 'template struct boost::bimaps::set_of'
party1.cpp:104:64: error: expected a type, got 'comp_pointer'
party1.cpp:104:70: error: template argument 1 is invalid
party1.cpp:104:85: error: invalid type in declaration before ';' token
typedef std::set<int> ruleset;
struct ruleset_cmp {
bool operator()(const ruleset *lhs, const ruleset *rhs) const
{
return ((*lhs) < (*rhs));
}
};
typedef boost::bimap<set_of<ruleset *, ruleset_cmp>, int> megarulebimap;
Okay. The above snippet works. It appears a functor needs to be used here.
In header:
list< SKPair<VALUETYPE> > *values[256];
In implementation:
const list< SKPair<VALUETYPE> > *bucket = values[0];
typename list< SKPair<VALUETYPE> >::iterator it = bucket.begin();
The gcc compiler complains about the second line:
error: request for member ‘begin’ in ‘bucket’, which is of non-class type ‘const std::list<SKPair<int>, std::allocator<SKPair<int> > >*’
(Here in main I create a test instance of my class where VALUETYPE is int.) Any idea what I'm doing wrong?
Write:
typename list< SKPair<VALUETYPE> >::iterator it = bucket->begin();
The -> is needed here.
bucket is declared as a pointer, so you need a dereferencing operator to access its members:
auto it = bucket->begin();
Should do the trick if you have C++11's auto available.