如何让 `std::basic_string<CustomClass>` 编译?

Posted

技术标签:

【中文标题】如何让 `std::basic_string<CustomClass>` 编译?【英文标题】:How to get `std::basic_string<CustomClass>` to compile? 【发布时间】:2012-09-05 21:48:47 【问题描述】:

好的,我通常能够阅读、理解和修复编译器错误。但有了这个,我想我需要帮助。

我想要一个std::basic_string&lt;CustomClass&gt;,其中CustomClass 是一个类。我不想为它编写自定义 char_traits 和分配器类,除非绝对必要(即,如果可能,我想使用 std::char_traits&lt;CustomClass&gt;std::allocator&lt;CustomClass&gt;)。

如果我在 CustomClass 中没有构造函数,它编译得很好。一加就报错:

调用'std::__1::basic_string&lt;CustomClass, std::__1::char_traits&lt;CustomClass&gt;, std::__1::allocator&lt;CustomClass&gt; &gt;::__rep'的隐式删除默认构造函数

    #include <iostream>
    #include <string>
    //#include <vector>

    class CustomClass;

    typedef std::basic_string<CustomClass> InstanceString;
    typedef std::basic_string<int> IntString;

    class CustomClass
    
    public:
        CustomClass()
            : m_X()
        
        

        CustomClass(const int x)
            : m_X(x)
        
        

    private:
        int     m_X;
    ;

    int main(int argc, const char * argv[])
    
        // This compiles fine
        IntString s1(1, 2, 5);

        // This would compile fine if there were no explicit constructors in Instance
        //InstanceString s2e = InstanceString(Instance(), Instance(), Instance());

        // This generates errors
        InstanceString s2 = InstanceString(CustomClass(1), CustomClass(3), CustomClass(5));

        std::cout << "Hello, World!\n";
        return 0;
    

我知道这可能与隐式/显式构造函数、复制/移动语义和类似的东西有关。

我的问题是:

如何编译它(即我应该在类中添加什么构造函数/东西) 以及如何系统地找出如何修复这些类型的编译错误?

【问题讨论】:

等等.. 为什么你甚至想要basic_string 中的自定义类?哪些功能让您这样做?! 没有其他 STL 容器保证最后一个值初始化哨兵? ;) Instance 必须是 POD 或标准布局(忘记哪个)。我认为关键部分是默认构造函数必须是=default,以及复制构造函数和析构函数。 substr 与复杂的字符类型一起使用(如果可能的话)会使效率低下的函数更加如此...... 只需使用Boost.Range,例如my_vec | boost::adaptors::sliced(first, last). 【参考方案1】:

从右边开始描述字符串库[strings.general]/1的第一句:

本条款描述了用于操作任何非数组 POD 类型序列的组件。在本条款中,此类类型称为 char-like 类型,而 char-like 类型的对象称为 char-like 对象或简称为字符。

CustomClass 不是 char-like 类型,因为它不是 POD 类型,因此它不能存储在 basic_string 中。

libc++ 实现无法编译,因为它使用了短字符串优化,并且这样做假定可以在联合中保存 CharT 数组而不提供自定义构造函数。

【讨论】:

感谢您提供具体信息。我感觉对于被认为是类似 char 的类型会有严格的限制,但你已经确认了。【参考方案2】:

如你所说,错误信息显示

Call to implicitly-deleted default constructor of 'std::__1::basic_string, std::__1::allocator >::__rep'

我很确定__rep 是你的CustomClass。它是说它正在尝试调用默认构造函数,但这已被隐式删除(通过您提供自己的构造函数)。我猜basic_string 使用std::is_default_constructible&lt;&gt;。因此,您需要使用

提供一个默认构造函数
CustomClass() = default;

正如 Mooing Duck 在 cmets 中所建议的那样。

它看起来很可能实际上使用了std::is_trivially_default_constructible&lt;&gt;,这限制了你的类也必须是可简单构造的。

【讨论】:

我认为你是对的。我已经用CustomClass() = default; 替换了CustomClass() : m_X(x) 构造函数,它编译正常。但是现在当我尝试将其更改为具有 int 和 std::vector 时,它再次中断。我将不得不阅读更多关于 basic_string 期望的内容。 @DmitriShuralyov:它不适用于std::vector&lt;&gt;,因为向量不是简单可构造的。您可能应该接受 Mankarse 的回答而不是我的回答,因为它解释了为什么事情是这样的,而我的回答只是解释了您班级的要求。 其实__rep在文件中定义为struct __rep union __long __l; __short __s; __raw __r; ; ; @DmitriShuralyov:原来如此。我认为__short 包含CustomClass 我仍然需要弄清楚CustomClass() = default;CustomClass() : m_X() 之间的区别,只是为了提高我的错误理解能力。但首先我必须了解constructor = default 的含义...【参考方案3】:

简而言之,不能使用自定义的class,因为短字符串优化可能会使用union

但是,您可以使用 enum 类型。

要正确完成这项工作需要做很多工作,而且您确实需要为您的类型实现std::char_traits

【讨论】:

以上是关于如何让 `std::basic_string<CustomClass>` 编译?的主要内容,如果未能解决你的问题,请参考以下文章

将 std::basic_string<Char> 转换为字符串

std::basic_string<TCHAR> 在 Windows 上会比 std::wstring 更可取吗?

错误 C3867 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::c_s

传递给 std::basic_string 的分配器能否将其方法设为虚拟

VS错误C++:不存在从 "WCHAR [260]" 转换到 "std::basic_string<char," 的适当构造函数

no suitable ctr exists to convert from 'int' to 'std::basic_string<char,std::char_tra