【问题标题】:Custom Array Class: Constructor for Initialization of List自定义数组类:初始化列表的构造函数
【发布时间】:2015-06-28 05:04:19
【问题描述】:

我正在使用 C++ 编写一个自定义数组类(作为自导练习),但我不确定如何创建一个构造函数,让我可以按照以下方式进行操作:

#include "array.h"
#include <iostream>
int main()
{
    array<int> test = {1, 2, 3, 4};
    std::cout << test(1) << std::endl;
    return 0;
}

编译器(VS Express 2013)给我的错误是“没有构造函数 array::array [with T = int] 的实例”与参数列表匹配。参数类型是 (int, int, int, int)。”

我不确定枚举一组元素的构造函数叫什么。我知道我已经正确地超载了operator()(const int&amp;)。我也知道这(出于我不清楚的原因)有效:

#include "array.h"
#include <iostream>
int main()
{
    array<char> test = "abcd";
    std::cout << test(1) << std:: endl; // prints 'a', as expected. 
    std::cout << test(4) << std::endl; // prints 'd', as expected.
    return 0;
}

这是通过array(const T[]) 构造函数实现的:array&lt;int&gt; test = {1, 2, 3, ..., n} 案例的解决方案是否类似?

提前感谢您的任何指导。

编辑:包括下面的代码,以防万一。

template<typename T>
class array
{
public:
    typedef T* iterator;
    typedef const T* const_iterator;
private:
    iterator head;
    unsigned long elems;
public:
    array()
        : head(nullptr)
        , elems(0) {}
    array(const unsigned long &size)
        : head(size > 0 ? new T[size] : nullptr)
        , elems(size) {}
    array(const T[]);
    array(const array&);
    ~array() { delete[] head; }

    iterator begin() const { return head; }
    iterator end() const { return head != nullptr ? &head[elems] : nullptr; }
    unsigned long size() const { return elems; }

    array& operator=(const array&);
    T& operator()(const unsigned long&);
};

template<typename T>
array<T>::array(const T rhs[])
{
    unsigned long size = sizeof(rhs) / sizeof(T);
    head = new T[size];
    iterator pointer = begin();
    for (const_iterator i = &rhs[0]; i != &rhs[0] + size; i++)
        *pointer++ = *i;
}

template<typename T>
array<T>::array(const array<T> &rhs)
{
    head = new T[rhs.size()];
    iterator pointer = begin();
    for (const_iterator i = rhs.begin(); i != rhs.end(); i++)
        *pointer++ = *i;
}

template<typename T>
array<T>& array<T>::operator=(const array<T> &rhs)
{
    if (this != &rhs)
    {
        delete[] head;
        head = new T[rhs.size()];
        iterator pointer = begin();
        for (const_iterator i = rhs.begin(); i != rhs.end(); i++)
            *pointer++ = *i;
    }
    return *this;
}

template<typename T>
T& array<T>::operator()(const unsigned long &index)
{
    if (index < 1 || index > size())
    {
        // Add some error-handling here.
    }
    return head[index - 1];
}

【问题讨论】:

  • 您的array class template 代码在哪里?
  • 这是我明显的遗漏:道歉。我已经把它包括在上面了。
  • sizeof(rhs) in array&lt;T&gt;::array(const T rhs[]) 肯定不是你想的那样。
  • warning: sizeof on array function parameter will return size of 'const char *' instead of 'const char []' [-Wsizeof-array-argument].

标签: c++


【解决方案1】:
#include <initializer_list>

// ...

template <typename T>
class array
{   
    // ... 
    array(std::initializer_list<T> il);    

// ...    
template <typename T>
array<T>::array(std::initializer_list<T> il)
{
    unsigned long size = il.size();
    head = new T[size];
    iterator pointer = begin();
    for (const T& i : il)
        *pointer++ = i;
}

// ...
array<int> test = {1, 2, 3, 4};

DEMO


建议的改进:

  1. array(const T rhs[]); 等价于array(const T* rhs);,即一个指针,这意味着sizeof(rhs) / sizeof(T) 表达式不会给你项目的数量。如果您想要const char* 的特殊构造函数,则考虑整个array&lt;char&gt; 特化,或者如果T 不是char,则至少从重载决议中禁用此构造函数

  2. head = new T[size]; 默认初始化所有元素(为T 类型的每个实例调用默认构造函数)。然后调用赋值操作:*pointer++ = *i;。这可以通过使用 placement-new 来改进,例如 ::new ((void*)ptr) T(*i);,其中 ptr 是指向未初始化的原始内存缓冲区的指针,例如 new char[sizeof(T)*size] 或从 get_temporary_buffer 返回。


如果您想知道为什么以下操作 array&lt;char&gt; test = { "abcd" };您当前的 实现一起工作,那么这里有一个解释:

  1. array&lt;T&gt; 类有一个采用const T[] 的构造函数,对于T=char,它被实例化为array&lt;char&gt;::array(const char*)

  2. List-initialization可以用来调用对象的构造函数。

  3. 你的 const T[] 构造函数不是显式的,这意味着你可以使用 copy-initialization 语法,如下所示:

    array<char> test = { "test" };
    
  4. T=char 的表达式 sizeof(rhs) / sizeof(T) 尽管如上所述无效,但计算结果为 sizeof(char*) / sizeof(char),即(最可能)4 / 1 = 4

  5. 你用于初始化的"test"正好有4个字母,你的运气。

【讨论】:

  • 感谢 Piotr 提供如此详尽的回答。一个问题:std::initializer_list&lt;T&gt; 如何知道传递的参数数量?不就是一对指针(en.cppreference.com/w/cpp/header/initializer_list)吗?给定{1, 2, 3, 4} 之类的内容,这些指针是如何构造的?
  • 它是一个编译时对象,编译器统计它们,使用.size()成员函数知道有多少个。
猜你喜欢
  • 2013-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多