Reputation: 173
I am embedding a boost::bimap in a templated class, and after much trial-and-error I have discovered something that compiles and something that does not. I am using g++ (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6) and Boost 1.55. I will give the full code in Example 1 and only the changed portions for Example 2 and Example 3. The function does not do anything useful, just testing the syntax and the compiler here.
Example 1 that does compile (complete listing):
#include <string>
#include <boost/bimap/bimap.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap/tags/tagged.hpp>
typedef double Address;
struct Label1 {};
struct Label2 {};
template< class TemplateParameter >
class Test
{
private:
typedef boost::bimaps::tagged< std::string, Label1 > KeyType;
typedef boost::bimaps::tagged< Address, Label2 > ValueType;
// No changes after this line in Example 2 or Example 3
typedef boost::bimaps::unordered_set_of< KeyType > KeySet;
typedef boost::bimaps::set_of< ValueType > ValueSet;
typedef boost::bimaps::bimap < KeySet, ValueSet > BidirectionalMap;
typedef typename BidirectionalMap::value_type Record;
// Create the bimap
BidirectionalMap TheBimap;
void aFunction ( const Address & AnAddress,
const TemplateParameter & Parameters )
{
auto NewRecord = TheBimap.insert( Record( "TheGivenAdddress", AnAddress ) );
auto ByAddress = TheBimap.by< Label1 >().find( "TheGivenAdddress" );
auto ByNumber = TheBimap.by< Label2 >().find( AnAddress );
}
};
I would like to encapsulate the labels inside the template class as there is no need for them to be known outside of the class. Ideally they should be private, but in order to avoid that access permissions create any problems, they are declared as public.
Example 2 that does not compile (except):
typedef double Address;
template< class TemplateParameter >
class Test
{
public:
struct Label1 {};
struct Label2 {};
private:
typedef boost::bimaps::tagged< std::string, Label1 > KeyType;
typedef boost::bimaps::tagged< Address, Label2 > ValueType;
Both lines where the bimap is accessed by the label produces the following message:
error: expected primary-expression before ‘>’ token
auto ByAddress = TheBimap.by< Label1 >().find( "TheGivenAdddress" );
This can be understood by Label1 needs full qualification, from being a part of the templated class, as follows.
auto ByAddress = TheBimap.by< Test<TemplateParameter>::Label1 >().find( "TheGivenAdddress" );
However the very same error is produced. Question 1: Does anyone understand why?
The real issue and reason for using the template class Test is that I want the type of Label 1 to be the template parameter. Thus, reverting to Example 1 and only replacing std::string
with the template parameter.
Example 3 that does not compile (except):
typedef double Address;
struct Label1 {};
struct Label2 {};
template< class TemplateParameter >
class Test
{
private:
typedef boost::bimaps::tagged< TemplateParameter, Label1 > KeyType;
typedef boost::bimaps::tagged< Address, Label2 > ValueType;
Again, both lines which access the map by the tags produces the above compilation error. Before rewriting the code to use "left" and "right" views, it would be good if anyone could help me understand Question 2: Why is it not possible to use a template parameter in the definition of the tagged type?
Thanks for all input!
Upvotes: 4
Views: 428
Reputation: 393114
The second case necessitates template
qualification. The reason is that Label1
and Label2
are now dependent names.
auto ByAddress = TheBimap.template by<Label1>().find("TheGivenAdddress");
auto ByNumber = TheBimap.template by<Label2>().find(AnAddress);
See Where and why do I have to put the "template" and "typename" keywords?
Question 2: Why is it not possible to use a template parameter in the definition of the tagged type?
The same reason. You may also need typename
qualification there.
#include <string>
#include <boost/bimap/bimap.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap/tags/tagged.hpp>
typedef double Address;
namespace bm = boost::bimaps;
template <class T>
class Test {
private:
typedef bm::bimap<
bm::unordered_set_of<bm::tagged<T, struct key_idx> >,
bm::set_of <bm::tagged<Address, struct value_ix> >
> BidirectionalMap;
typedef typename BidirectionalMap::value_type Record;
BidirectionalMap _theBimap;
public:
void aFunction(const Address &anAddress, T const& parameters)
{
auto newRecord = _theBimap.insert(Record("TheGivenAdddress", anAddress));
auto byNumber = _theBimap.template by<value_ix>().find(anAddress);
auto byAddress = _theBimap.template by<key_idx>().find(parameters);
(void) newRecord, (void) byAddress, (void) byNumber;
}
};
int main() {
Test<std::string> t;
t.aFunction(3.14, "hello");
}
To really keep the tag types local to the class add
struct key_idx;
struct value_idx;
(no need to define them). See it live
Upvotes: 2