首页 文章

std :: map中的C 11类作为私有构造函数的值

提问于
浏览
2

这是类的简化版本,它作为值存储在一个在VS2008中正常工作的 Map 中(注意 all 成员是私有的):

class Value{
    friend class FriendClass;
    friend class std::map<std::string, Value>;
    friend struct std::pair<const std::string, Value>;
    friend struct std::pair<std::string, Value>;

    Value() {..}
    Value(Value const& other) {..}

    ... rest members...
};

代码(从FriendClass调用,因此可以访问私有构造函数):

FriendClass::func()
{
    std::map<const std::string, Value> map;
    map.insert(std::make_pair(std::string("x"), Value()));
}

这不会编译VS2008中的任何错误,但在VS2015 / C 11上失败:

file.cpp(178): error C2664: 'std::_Tree_iterator>>> std::_Tree>::insert(std::_Tree_const_iterator>>>,const std::pair &)': cannot convert argument 1 from 'std::pair' to 'std::pair &&'
      with
      [
          _Kty=std::string,
          _Ty=Value,
          _Pr=std::less,
          _Alloc=std::allocator>
      ]
      and
      [
          _Kty=std::string,
          _Ty=Value
      ]
  file.cpp(178): note: Reason: cannot convert from 'std::pair' to 'std::pair'
      with
      [
          _Kty=std::string,
          _Ty=Value
      ]
  file.cpp(178): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

如果我将Value复制构造函数设置为public,它在VS2015中编译也很好 .

但这是有目的的私有,只有std :: map和std :: pair可用 . 但是,似乎在C 11中额外的朋友访问也需要申报 . 这些是哪些?

谢谢 .

1 回答

  • 0

    我没有访问你提到的编译器,但这是我在g 5.3上看到的 .

    请考虑以下基本相同版本的问题:

    #include <map>                                                                                                                             
    #include <utility>
    
    
    class foo
    {
        friend std::pair<const int, foo>;
    
        foo(const foo &other){}
    
    public:
        foo(){}
    };
    
    
    int main()
    {
        using map_t = std::map<int, foo>;
    
        map_t m;
        m.insert(std::make_pair(2, foo()));
        // m.emplace(2, foo());
    }
    

    (默认的ctor是 public ,但这不是必需的,只是缩短了示例 . )

    main 中,请注意两行

    m.insert(std::make_pair(2, foo()));
    // m.emplace(2, foo());
    

    反转注释构建正常,但显示的版本不是:

    /usr/include/c++/5/bits/stl_pair.h: In instantiation of ‘constexpr    std::pair<_T1, _T2>::pair(_U1&&, const _T2&) [with _U1 = int; <template-parameter-2-2> = void; _T1 = int; _T2 = foo]’:
    /usr/include/c++/5/bits/stl_pair.h:281:72:   required from ‘constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename   std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = foo; typename std::__decay_and_strip<_T2>::__type = foo; typename std::__decay_and_strip<_Tp>::__type = int]’
    stuff.cpp:21:34:   required from here
    stuff.cpp:9:2: error: ‘foo::foo(const foo&)’ is private
     foo(const foo &other){}
     ^
    

    查看源代码 std_pair.h 表明它确实在尝试调用复制构造函数 . 不幸的是,你 friend ed std::pair ,但不是 std::make_pair .

    emplace 版本没有这个问题,但我怀疑这是依赖于实现的 . 通常,如果您希望容器存储完全不透明的类,我建议您使用 std::shared_ptr 的容器 . 这允许您完全指定哪个函数/类可以在您自己的代码中创建/复制对象,并且不对库的代码进行任何假设 .

相关问题