Страницы

Поиск по вопросам

понедельник, 24 февраля 2020 г.

Конструктор класса с++, принимающий на вход многомерный initalizer_list

#cpp #qtcreator #g++ #шаблоны_с++


Задался задачей по написанию шаблонного контейнера, который в памяти хранится как
одномерный. При этом со всей необходимой математикой и прочими преобразованиями. Для
начала хотелось написать конструктор, который принимал бы на вход многомерный initalizer_list
(brace-enclosed initializer_list). 

Начал реализацию с этого: 

#ifndef ARRAY_H
#define ARRAY_H

#include 
#include 
#include 

using namespace std;

template 
class array{
private:

    T* data;
    int* shape;

public:

    array(){
        this->data = new T[1]{1};
        this->shape = new int[1]{1};
    }

    template 
    array(initializer_list  input_data){

        const char* TypeName = typeid(input_data).name(); //
        const char* iter = TypeName;                      //
        iter += strlen(TypeName) - 1;                     //
                                                          // Костыльно определяем
размерность
        int dimensionality = 0;                           //
        while (*iter-- == 'E'){                           //
            dimensionality++;                             //
        }                                                 //

        this->shape = new int [dimensionality];
        this->shape[0] = input_data.size();               // Костыльно    заполняем shape

        int input_size = input_data.size();

        this->data = new T [input_data.size()];                                 //
                                                                                //
        const B* item = input_data.begin();                                     //
                                                                                //
        for (int index_data = 0 ; index_data < input_size ; index_data++){      //
Костыльно заполняем data
            this->data[index_data] = *item++;                                   //
        }                                                                       //

    }

    int size(){
        return this->shape[0];
    }

};

#endif // ARRAY_H


При этом интересующий конструктор работает на одномерных объектах, но, при выполнении
следующего кода:

#include 
#include "array.h"

using namespace std;

int main(){

    array  first_test_array;

    cout << "Тест конструктора без аргументов :\n" << first_test_array.size() << endl;

    array  second_test_array {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    cout << "Тест конструктора с одномерным initializer_list :\n" << second_test_array.size()
<< endl << endl;

    array  third_test_array {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}}; // Падает здесь

    cout << "Тест конструктора с многомерным initializer_list :\n" << third_test_array.size()
<< endl;

}


Пишет вот такую ошибку:

In funstion 'int main()':
/home/artyom/CPP/array/main.cpp:16: ошибка: no matching function for call to 'array::array()'
 array  third_test_array {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
                                                                 ^
/home/artyom/CPP/array/main.cpp:16: candidates are:
/home/artyom/CPP/array/main.cpp:2: In file included from ../array/main.cpp:2:0:
/home/artyom/CPP/array/array.h:25: template array::array(std::initializer_list)
 array(initializer_list  input_data){
 ^

/home/artyom/CPP/array/array.h:25: note:   template argument deduction/substitution
failed:
/home/artyom/CPP/array/main.cpp:16: note:   candidate expects 1 argument, 2 provided
 array  third_test_array {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
                                                                 ^
/home/artyom/CPP/array/main.cpp:2: In file included from ../array/main.cpp:2:0:
/home/artyom/CPP/array/array.h:19: array::array() [with T = int]
 array(){
 ^
/home/artyom/CPP/array/array.h:19: note:   candidate expects 0 arguments, 2 provided
/home/artyom/CPP/array/array.h:11: constexpr array::array(const array&)
class array{
   ^
/home/artyom/CPP/array/array.h:11: note:   candidate expects 1 argument, 2 provided
/home/artyom/CPP/array/array.h:11: constexpr array::array(array&&)
/home/artyom/CPP/array/array.h:11: note:   candidate expects 1 argument, 2 provide


Может ли мне кто-либо объяснить как это сделать?
    


Ответы

Ответ 1



Скорее всего вам поможет: http://christophercrouzet.com/blog/post/2015/01/12/Nested-Initializer-Lists-for-Multidimensional-Arrays Код можно посмотреть тут: https://github.com/christophercrouzet/m3ta/blob/master/src/m3ta/. Например, реализация вложенного initializer_list: https://github.com/christophercrouzet/m3ta/blob/master/src/m3ta/nestedinitializerlists.h

Ответ 2



Проблема в том, что в некоторых ситуациях типы не могут быть выведены для шаблонов. И наличие неявного std::initializer_list в передаваемых аргументах одна из таких ситуаций. Выдержка из Стандрарта 14.8.2.5/5: The non-deduced contexts are: ... A function parameter for which the associated argument is an initializer list ([dcl.init.list]) but the parameter does not have a type for which deduction from an initializer list is specified ([temp.deduct.call]). [ Example: template void g(T); g({1,2,3}); // error: no argument deduced for T — end example ] Чтобы Ваш код работал нужно добавить конструктор, принимающий например список списков std::initializer_list> или например список пар std::initializer_list>, если планируется использовать только пары во вложенных списках. Можно ещё явно преобразовать типы при вызове, но это, конечно, не удобно использовать: {std::initializer_list{0, 1}, std::initializer_list{2, 3}}

Ответ 3



У вас конструктор array(initializer_list input_data), следовательно ожидается массив объектов B. Вы же пытаетесь инициализировать его с помощью массива массивов объектов B. Думаю, что вам приедятся определить конструкторarray(initializer_list> input_data)

Комментариев нет:

Отправить комментарий