boost multi index container of template-dependent struct in template-class - c++

I want a multi-index-container in a class, that depends on a template-dependent class in the class.
Sounds complicated, here is the code:
#include <boost/unordered_map.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
template <typename Type>
class myDataContainer{
public:
struct DataStruct{
double t;
std::vector<Type> data;
};
// indices structs
struct TagTime{};
struct TagOrdered{};
typedef boost::multi_index::multi_index_container<
DataStruct,
boost::multi_index::indexed_by<
boost::multi_index::hashed_unique<boost::multi_index::tag<TagTime>, boost::multi_index::member<DataStruct, double, &DataStruct::t> >,
boost::multi_index::ordered_unique<boost::multi_index::tag<TagOrdered>, boost::multi_index::member<DataStruct, double, &DataStruct::t> > // this index represents timestamp incremental order
>
> InnerDataContainer;
typedef typename boost::multi_index::index<InnerDataContainer,TagTime>::type timestamp_view;
typedef typename boost::multi_index::index<InnerDataContainer,TagOrdered>::type ordered_view;
InnerDataContainer dataContainer;
void begin(){
ordered_view& ordView = dataContainer.get<TagOrdered>();
ordView.begin();
}
};
int main(int argc, char *argv[])
{
myDataContainer<float> data;
myDataContainer<float>::ordered_view& ordView = data.dataContainer.get<TagOrder>();
ordView.begin();
}
Without the myDataContainer::begin() function this code compiles, but with the myDataContainer::begin() I get the following error:
main.cpp: In member function 'void myDataContainer<Type>::begin()':
main.cpp:134:66: error: expected primary-expression before '>' token
main.cpp:134:68: error: expected primary-expression before ')' token
Am I missing something? Is this a bug in boost or is it not possible?`
Thanks in advance
veio

Because dataContainer is template parameter dependent, you need
ordered_view& ordView = dataContainer.template get<TagOrdered>();
In main() you use specific a specialization, so there are no dependent expressions any more.

Related

Cannot compile: error: expected primary-expression before '(' token

I cannot get this compile:
// main.cpp
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/tag.hpp>
using namespace boost::multi_index;
struct by_attrs{};
// Generic MultiIndex that wraps boost::multi_index
template<typename Container>
class MultiIndex
{
public:
typedef typename Container::template index<by_attrs>::type::iterator attr_iterator;
template<typename FromArgs, typename ToArgs>
std::pair<attr_iterator, attr_iterator>
fetch_range(FromArgs&& from, ToArgs&& to)
const
{
return std::pair<attr_iterator, attr_iterator>(
_container.get<by_attrs>().lower_bound(from),
_container.get<by_attrs>().upper_bound(to)
);
}
private:
Container _container;
};
class Foo
{
public:
int bar() const
{
return 1;
}
};
typedef multi_index_container<
Foo,
indexed_by<
ordered_unique<
tag<by_attrs>,
composite_key<
Foo,
const_mem_fun<
Foo,
int,
&Foo::bar
>
>
>
>
> FooMultiIndexContainer;
typedef MultiIndex<FooMultiIndexContainer> FooMultiIndex;
int main()
{
FooMultiIndex foo_index;
}
Error (g++ -std=c++11 main.cpp):
In member function 'std::pair<typename Container::index<by_attrs>::type::iterator, typename Container::index<by_attrs>::type::iterator> MultiIndex<Container>::fetch_range(FromArgs&&, ToArgs&&) const': main.cpp:28:55: error: expected primary-expression before '(' token 28 | return std::pair<attr_iterator, attr_iterator>(
You need to put a couple of templates here:
template<typename FromArgs, typename ToArgs>
std::pair<attr_iterator, attr_iterator>
fetch_range(FromArgs&& from, ToArgs&& to)
const
{
return std::pair<attr_iterator, attr_iterator>(
_container.template get<by_attrs>().lower_bound(from),
_container.template get<by_attrs>().upper_bound(to)
);
}
You may want to consult this thread on the use of typename and template in so-called dependent contexts: Where and why do I have to put the “template” and “typename” keywords?

std::unordered_map Error in declaration

In Execution.cpp, I need to add unordered_map. I used the following instruction:
#include <unordered_map>
std::unordered_map<StringRef, std::unordered_map<StringRef, struct IntRel>> BinaryRel;
but it invokes the following errors:
/usr/include/c++/4.8/bits/functional_hash.h:58:12: error: declaration of ‘struct std::hash<llvm::StringRef>’
struct hash;
/usr/include/c++/4.8/bits/hashtable_policy.h:1082:53: error: invalid use of incomplete type ‘struct std::hash<llvm::StringRef>’
using __ebo_h1 = _Hashtable_ebo_helper<1, _H1>;
You have to specialize std::hash for your StringRef type. For example:
#include <unordered_map>
struct StringRef {};
struct IntRel {};
namespace std {
template<>
struct hash<StringRef>
{
std::size_t operator()(const StringRef& s) const noexcept { return 0; }
};
}
int main()
{
std::unordered_map<StringRef, std::unordered_map<StringRef, struct IntRel>> BinaryRel;
}
Although I suggest better implementation of hashing function :D For this you can use one of existing specializations (std::hash<std::string> ? if your StringRef possibly contains std::string object).

How to declare a self-referential template typedef

Here's a small example which is substantially similar to what I'm trying to do:
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include <utility>
#include <vector>
struct foo {
const char * str;
};
typedef std::pair<float, float> fpair;
//typedef std::vector<boost::variant<int, fpair, foo, vlist>> vlist;
// ^ No...
//typedef std::vector<boost::variant<int, fpair, foo, boost::recursive_wrapper<vlist>>> vlist;
// ^ No...
//template <typename T = vlist<T> >
//using vlist = std::vector<boost::variant<int, fpair, foo, boost::recursive_wrapper<vlist>>>;
// ^ No...
template <typename T = vlist<T> >
using vlist = std::vector<boost::variant<int, fpair, foo, boost::recursive_wrapper<T>>>;
// Still no?
int main () {
std::cout << "Hello world\n";
}
The error I get with gcc 4.8 is:
test.cpp:12:33: error: expected nested-name-specifier before ‘vlist’
template <typename T = typename vlist<T>>
^
test.cpp:12:33: error: expected ‘>’ before ‘vlist’
The error with clang 3.6 is:
test.cpp:12:24: error: unknown type name 'vlist'
template <typename T = vlist<T>>
^
test.cpp:12:29: error: expected ',' or '>' in template-parameter-list
template <typename T = vlist<T>>
^
test.cpp:12:32: error: expected unqualified-id
template <typename T = vlist<T>>
^
3 errors generated.
(Edit: actually these errors are from slightly different versions of the above code, but they all give quite similar messages)
I looked at these earlier, slightly different questions, I'm still stumped:
How to declare a self referencing template type
How to properly declare a self-referencing template type?
Boost Fusion adapt declaration for a templated self referential structure
Does anyone know a trick for this, or is there some reason I'm not aware of that the compiler inherently isn't able to do this?
I believe you just want boost::make_recursive_variant:
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <utility>
#include <vector>
struct foo {
const char* str;
};
typedef std::pair<float, float> fpair;
typedef boost::make_recursive_variant<
int,
fpair,
foo,
std::vector<boost::recursive_variant_>
>::type vlist;
int main() {
std::vector<vlist> vec;
vec.push_back(4);
vec.push_back(fpair{1.0f, 2.0f});
vlist v2(vec);
}

How do I specify the type of a map used with a template?

I first have this simple example that works (my first time using maps). The type of the name-value pairs is a string to a function pointer respectively.
#include <iostream>
#include <map>
using std::cout;
int foo() {
return 243;
}
int main() {
std::map<std::string, int (*)()> list;
list["a"] = foo;
cout << list["a"](); // 243
}
Then I tried using a template to specify the type. Where it says int in the map instantiation is where I'd like to specify the type using a template. So I tried but I don't exactly know where to put <int> where I'm either calling the function or making the name-value pairs. This is what I tried:
#include <iostream>
#include <map>
using std::cout;
int foo() {
return 243;
}
int main() {
template <typename N>
std::map<std::string, N (*)()> list;
list["A"] = <int> foo; // right here where you see <int>
cout << list["A"]();
}
This doesn't work because I don't think I'm putting <int> in the right place. The errors I'm getting are:
/tmp/134535385811595.cpp: In function 'int main()':
/tmp/134535385811595.cpp:11: error: expected primary-expression before 'template'
/tmp/134535385811595.cpp:11: error: expected `;' before 'template'
/tmp/134535385811595.cpp:14: error: 'list' was not declared in this scope
/tmp/134535385811595.cpp:14: error: expected primary-expression before '<' token
/tmp/134535385811595.cpp:14: error: 'N' was not declared in this scope
Can anyone help?
template <typename N>
std::map<std::string, N (*)()> list;
template<typename> syntax is used for definitions of templates. Map class template is already defined elsewhere, you can only provide template parameters when you're instantiating it.
You can do what you want by wrapping your map in a class template:
template<typename ReturnType>
struct Wrapper {
std::map<std::string, ReturnType (*)()> m;
};
and then instantiate and use it like:
int foo() { }
Wrapper<int> w;
w.m["foo"] = foo;

Boost multi_index_container, get index by tag results in compiler error

So, I'm trying to dabble with the multi_index_container and am having a rather strange compiler error, first here is the simplest example to demonstrate my problem (I'm probably missing something stupidly simple)...
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/mem_fun.hpp>
namespace multi_index = boost::multi_index;
template <typename _IdType>
class A
{
public:
typedef _IdType IdType;
IdType getId() const { return id; }
private:
IdType id;
};
struct id_index{};
template <typename Traits>
class Container
{
typedef typename Traits::AType AType;
typedef typename AType::IdType IdType;
typedef typename multi_index::multi_index_container<
AType,
multi_index::indexed_by<
// sort by Id
multi_index::ordered_non_unique<multi_index::tag<id_index>, BOOST_MULTI_INDEX_CONST_MEM_FUN(AType, IdType, getId) >
>
> ASet;
typedef typename ASet::template index<id_index>::type::const_iterator a_it;
typedef typename ASet::template index<id_index>::type::reverse_iterator a_rit;
typedef typename ASet::template index<id_index>::type id_index_t;
public:
bool addA(AType const& cA)
{
const id_index_t& os = _cSet.get<id_index>(); // line 1: errors occur here
// .. do stuff
return true;
}
private:
// Instance of the container...
ASet _cSet;
};
struct ATraits
{
typedef A<int> AType;
};
int main(void)
{
Container<ATraits> container;
ATraits::AType a;
container.addA(a);
return 0;
}
The errors reported by g++ (gcc 4.4.4, linux) is:
error: expected primary-expression before ‘>’ token (# line 1)
error: expected primary-expression before ‘)’ token (# line 1)
So this was working fine till I converted the Container to a class template, after this, I get this error, and can't work out why..
Any ideas will be appreciated...
bool addA(AType const& cA)
{
const id_index_t& os = _cSet.template get<id_index>(); // line 1: errors occur here
// .. do stuff
return true;
}