To demonstrate my problem, consider this simple program that does not compile:
#include <boost/noncopyable.hpp>
#include <unordered_map>
class foo : boost::noncopyable { };
int main()
{
    std::unordered_map<int, foo> m;
    auto & element = m[0];
    return 0;
}
Using the current version of boost (1.52), Visual Studio 2012 returns the error:
cannot access private member declared in class 'boost::noncopyable_::noncopyable.
The operator [] for std::unordered_map returns a reference to the element at the provided key, which at first glance seems like it should work -- I've asked for a reference to the element, not a copy of it.
My understanding of the problem is this (which might be wrong, as I haven't used C++ in a while). If the key is not found, unordered_map creates a new element and returns a reference to the new element. boost::noncopyable defines a (private) copy constructor but not a move constructor, and so a move constructor is not generated by the compiler. In its operator[], std::unordered_map makes use of std::move, but since boost::noncopyable doesn't define a move constructor, it falls back to the copy constructor. Since the copy constructor is private, the compilation fails.
What prompted this post is that I'm trying to create an unordered_map of boost::signal2::signal, which inherits from boost::noncopyable. Short of hacking the boost library, is there a simple workaround I can do? Wrapping the signal in a unique_ptr is an option, but it seems to me I might be doing something wrong here.
I may have posted too soon! It appears impossible to add a subclass of boost::noncopyable to unordered_map. Insert, operator[], and emplace all use either a copy constructor (which is private), or a move operation (which doesn't exist for boost::noncopyable). To me this seems a major limitation. Is it even possible to create an unordered_map that contains boost::noncopyable objects? I'm explicitly not trying to copy them -- I want them to spend their entire lifespan inside the unordered_map.
It's not impossible to use a subclass of boost::noncopyable in an unordered_map, you simply have to define a move constructor for you type. C++ does not create a default move constructor if you've made your own copy construct (which is what boost::noncopyable does). Also, if it did define  default move constructor, it would try to call the parent's copy constructor which is private. So you must define a move constructor that doesn't try to call boost::noncopyable's copy constructor. For example this works fine:
#include <boost/noncopyable.hpp>
#include <unordered_map>
struct foo : public boost::noncopyable
{
    foo() = default;
    foo(foo&&) {}
};
int main()
{
    std::unordered_map<int, foo> m;
    auto & element = m[0];
    return 0;
}
                        This likely isn't exactly what you're looking for, but I figured I'd toss it out there. The one thing to note is the second value of the returned pair from emplace(), which indicates the second call does not introduce a new member, nor copy over the exiting member. 
Again, I don't know if this is closer to what you want, but worth a shot. I likely did something wrong, as I'm not overtly familiar with the C++11 standard library as others. Sorry about that if so.
Finally, please note this is not attempting to address the OP's request of using operator []() for insert+access. Rather, it attempts to simply get a boost::noncopyable derivation constructed into an unordered_map<>. To access you would likely need a combination of the below as well as an initial find() to determine if the tag exists initially.
Anyway...
#include <boost/noncopyable.hpp>
#include <iostream>
#include <unordered_map>
class Foo : public boost::noncopyable
{
public:
    Foo(int value) : value(value) {};
    void setValue(int value) { this->value = value; }
    int getValue() const { return value; }
private:
    int value;
};
int main(int argc, char *argv[])
{
    typedef std::unordered_map<std::string, Foo> MyMap;
    MyMap mymap;
    // throw ("test".1) into the map
    auto p = mymap.emplace("test", 1);
    auto q = mymap.emplace("test", 2); // should not overwrite the first.
    // dump content
    cout << p.first->second.getValue() << '(' << p.second << ')' << ' '
         << q.first->second.getValue() << '(' << q.second << ')' << endl;
    // modify through the second returned iterator/bool pair.
    q.first->second.setValue(3);
    // dump again, see if p was also updated.
    cout << p.first->second.getValue() << '(' << p.second << ')' << ' '
         << q.first->second.getValue() << '(' << q.second << ')' << endl;
    return 0;
}
Output
1(1) 1(0)
3(1) 3(0)
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With