【问题标题】:Compiler error C2664 using std::map and custom class as its value使用 std::map 和自定义类作为其值的编译器错误 C2664
【发布时间】:2023-04-01 07:54:01
【问题描述】:

我在这个问题上做了很多搜索,但没有一个答案有帮助。

我的设置

  • Visual Studio 2017
  • Windows 10

我有一个大型代码库,其中一个类是 Bar


// Bar.h

class Bar {
public:
   Bar();
   ~Bar();

public:
    ... // a long list of other methods.

private:
    std::map<std::string, Foo> m_foos;

};

然后在它的实现中

// Bar.cpp

Bar::Bar() {
   m_foos.insert(std::make_pair(std::string("id"), Foo()));              // Error 1
   m_foos.insert({std::string("id"), Foo()});                            // Error 2
   m_foos.insert(std::pair<std::string, Foo>(std::string("id"), Foo())); // Error 3
}

尝试编译上面的代码给了我:

错误 1

error C2664: 'std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<_Ty>>> std::_Tree<std::_Tmap_traits<_Kty,Foo,_Pr,_Alloc,false>>::insert(std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<_Ty>>>,const std::pair<const _Kty,Foo> &)': cannot convert argument 1 from 'std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char>>,Foo>' to 'std::pair<const _Kty,_Ty> &&'

错误 2

error C2664: 'std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<_Ty>>> std::_Tree<std::_Tmap_traits<_Kty,Foo,_Pr,_Alloc,false>>::insert(std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<_Ty>>>,const std::pair<const _Kty,Foo> &)': cannot convert argument 1 from 'initializer list' to 'std::pair<const _Kty,_Ty> &&'

错误 3

error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'std::pair<std::basic_string<char,std::char_traits<char>,std::allocator<char>>,Foo>'

但是,使用相同的设置和编译器,以下大大简化的代码可以成功编译:

#include "pch.h"
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <map>
#include <string>
#include <vector>

class Foo {
public:
    Foo() { mi = 1; }
    ~Foo() {}

private:
    int mi;
};

class MyFoo : public Foo {
public:
    MyFoo() :Foo() {
        mj = 2;
        mk = nullptr;
    }
    ~MyFoo() {}

private:
    int mj;
    int* mk;
};

class YourFoo : public Foo {
public:
    YourFoo() :Foo() { mj = 2; }
    ~YourFoo() {}

private:
    int mj;
};

int main()
{
    std::map<int, Foo> yourmap;
    yourmap.insert(std::make_pair(3, Foo()));
    yourmap.insert({ 4, Foo() });
    yourmap.insert(std::pair<int, Foo>(5, Foo()));

}

我哪里错了?

更新

所以我终于可以重现它了。这是因为有问题的类层次结构删除了它们的复制构造函数和operator =

修改后的例子可以重现错误。

#include "pch.h"
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <map>
#include <string>
#include <vector>

class Foo {
public:
    Foo() { mi = 1; }
    ~Foo() {}

    // NO COPIES.   
    Foo(const Foo &) = delete;
    Foo& operator = (const Foo &) = delete;

private:
    int mi;
};

class MyFoo : public Foo {
public:
    MyFoo() :Foo() {
        mj = 2;
        mk = nullptr;
    }
    ~MyFoo() {}

    // NO COPIES.
    MyFoo(const MyFoo &) = delete;
    MyFoo& operator = (const MyFoo &) = delete;

private:
    int mj;
    int* mk;
};

class YourFoo : public Foo {
public:
    YourFoo() :Foo() { mj = 2; }
    ~YourFoo() {}

    // NO COPIES.
    YourFoo(const YourFoo &) = delete;
    YourFoo& operator = (const YourFoo &) = delete;

private:
    int mj;
};


int main()
{
    std::map<int, Foo> yourmap;
    yourmap.insert(std::make_pair(3, Foo()));
    yourmap.insert({ 4, Foo() });
    yourmap.insert(std::pair<int, Foo>(5, Foo()));

}

所以我猜问题是std::map 必须将元素复制到它的内存空间中。然后它只是碰到没有复制构造函数的类并抱怨。但是错误消息是如此具有误导性,以至于我无法弄清楚。实际的类层次结构非常庞大,所以我没有看到那些被删除的部分。猜猜有人不想重复这些东西。

如果有人可以在我的问题开头附近指导如何破译编译器错误消息,以便我可以更好地了解在哪里查看,我们将不胜感激!

【问题讨论】:

  • 第二个例子中MyFooYourFoo的作用是什么?
  • 你使用什么编译器?它适用于我在 Windows 10 上的 Visual Studio 2017。
  • 在 windows 10 的 VS2017 中成功编译相同的代码
  • @Scheff 所以你的意思是这些错误很可能是假的。我见过很多假的错误信息,但这一条真的让我着迷。事实上,我必须逐步改变,直到找到代码库之间的差异。
  • @PiotrSiekański 这是 VS2017 的。有趣的是第二个示例使用相同的编译器。

标签: c++ visual-studio c++11 stdmap std-pair


【解决方案1】:

没有可用的复制构造函数/复制赋值的类的实例仍然可以在std::map 中使用,但需要使用一些特殊技巧:

  • emplace 而不是 insert(在适当的位置构造地图条目)
  • 使用std::piecewise_construct

在 cppreference.com 上了解更多信息:std::map::emplace

应用于 OPs 示例代码:

#include <iostream>
#include <map>
#include <string>

class Foo {
public:
    Foo(): mi("1") { }
    ~Foo() = default;
    Foo(const Foo&) = delete;
    Foo& operator=(const Foo&) = delete;

private:
    std::string mi;
};

std::ostream& operator<<(std::ostream &out, const Foo &foo)
{
  return out << "Foo()";
}

int main()
{
  std::map<std::string, Foo> yourmap;
#if 0 // WON'T COMPILE due to deleted Foo::Foo(const Foo&):
  yourmap.insert(std::make_pair("3", Foo()));
  yourmap.insert({ "4", Foo() });
  yourmap.insert(std::pair<std::string, Foo>("5", Foo()));
#endif // 0
  yourmap.emplace(std::piecewise_construct,
    std::forward_as_tuple("3"), // std::string("3")
    std::forward_as_tuple()); // Foo()
  // check result
  for (auto &entry : yourmap) {
    std::cout << '"' << entry.first << "\": " << entry.second << '\n';
  }
}

输出:

"3": Foo()

Live Demo on coliru

【讨论】:

    【解决方案2】:

    我在 Visual Studio Community 2017 上构建这个程序没有任何问题:

    #include "pch.h"
    #include <iostream>
    #include <map>
    
    class Foo {
    public:
       Foo();
    };
    
    Foo::Foo() {
       std::cout << "Foo is being constructed\n";
    }
    
    class Bar {
    public:
       Bar();
       ~Bar();
    
    private:
       std::map<std::string, Foo> m_foos;
    
    };
    
    Bar::Bar() {
       m_foos.insert(std::make_pair(std::string("id"), Foo()));              
       m_foos.insert({ std::string("id"), Foo() });                            
       m_foos.insert(std::pair<std::string, Foo>(std::string("id"), Foo())); 
    }
    
    Bar::~Bar() {
       std::cout << "Destructing bar\n";
    }
    
    int main()
    {
       Bar bar = Bar();
       std::cout << "Hello World!\n"; 
    }
    

    控制台上的程序输出:

    C:\Users\me\source\repos\SO0\Debug>SO0.exe
    Foo is being constructed
    Foo is being constructed
    Foo is being constructed
    Hello World!
    Destructing bar
    

    【讨论】:

      【解决方案3】:
      #include "pch.h"
      #include <iostream>
      #include <algorithm>
      #include <cstdio>
      #include <map>
      #include <string>
      #include <vector>
      
      class Foo {
      public:
          Foo() { mi = 1; }
          ~Foo() {}
      
          // NO COPIES.   
          Foo(const Foo &) = delete;
          Foo& operator = (const Foo &) = delete;
      
      private:
          int mi;
      };
      
      class MyFoo : public Foo {
      public:
          MyFoo() :Foo() {
              mj = 2;
              mk = nullptr;
          }
          ~MyFoo() {}
      
          // NO COPIES.
          MyFoo(const MyFoo &) = delete;
          MyFoo& operator = (const MyFoo &) = delete;
      
      private:
          int mj;
          int* mk;
      };
      
      class YourFoo : public Foo {
      public:
          YourFoo() :Foo() { mj = 2; }
          ~YourFoo() {}
      
          // NO COPIES.
          YourFoo(const YourFoo &) = delete;
          YourFoo& operator = (const YourFoo &) = delete;
      
      private:
          int mj;
      };
      
      
      int main()
      {
          std::map<int, std::shared_ptr<Foo> > objects;
          objects.insert(std::pair<int, std::shared_ptr<Foo> >(0, new Foo()));
      
      }
      

      【讨论】:

      • 好的。那么在不修改构造器方案的情况下,唯一的办法就是通过共享指针使用动态分配?
      猜你喜欢
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-05
      • 2012-05-15
      相关资源
      最近更新 更多