Невозможно использовать список инициализаторов для присвоения значений, если структура содержит конструктор

#c #std #operator-keyword #stdmap #initializer-list

#c #std #operator-ключевое слово #stdmap #список инициализаторов

Вопрос:

Я использовал список инициализаторов для создания объекта и присвоения его карте с int помощью ключа. В случае простой структуры временная структура может быть создана с помощью списка инициализаторов.

следовательно, я делаю что-то подобное, что абсолютно допустимо

 struct fileJobPair {
        int file;
        int job;
};

map<int, fileJobPair> mp;
mp[1] = {10, 20};
mp[2] = {100, 200};
mp[3] = {1000, 2000};
 

Но если я добавлю конструктор в структуру, я получаю сообщение об ошибке

 file.cpp: In function ‘int main()’:
file.cpp:18:21: error: no match for ‘operator=’ (operand types are ‘std::map<int, fileJobPair>::mapped_type’ {aka ‘fileJobPair’} and ‘<brace-enclosed initializer list>’)
   18 |      mp[1] = {10, 20};
      |                     ^
file.cpp:4:8: note: candidate: ‘constexpr AfileJobPairamp; AfileJobPair::operator=(const AfileJobPairamp;)’
    4 | struct fileJobPair {
      |        ^~~~~~~~~~~~
file.cpp:4:8: note:   no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘const fileJobPairamp;’
file.cpp:4:8: note: candidate: ‘constexpr fileJobPairamp; fileJobPair::operator=(fileJobPairamp;amp;)’
file.cpp:4:8: note:   no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘fileJobPairamp;amp;’
 

Это то, что я пробовал :

 struct fileJobPair {
        int file;
        int job;
        fileJobPair()
        {
                file = job = 0;
        }
};

int main()
{
            map<int, fileJobPair> mp;
            mp[1] = {10, 20};
            mp[2] = {100, 200};
            mp[3] = {1000, 2000};
            for(int i =1;i<=3;i  )
            {
                cout<< mp[i].file <<" "<< mp[i].job<<endl;
             }
            return 0;
}
 

Почему я получаю ошибку и как именно она работает внутри?

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

1. fileJobPair имеет конструктор по умолчанию, поэтому вы не можете использовать инициализаторы для его инициализации

2. Эта проблема возникает только тогда, когда я добавляю конструктор в эту простую структуру. ТАК точно ли это работает внутри

3. Это не проблема map . Вы получите то же самое с fileJobPair f; f = {10,20}; . Разница в том, что после добавления пользовательского конструктора по умолчанию fileJobPair он больше не является агрегатом . Подробности смотрите здесь: en.cppreference.com/w/cpp/language/aggregate_initialization .

4. @DanielLangr большое спасибо, это прояснило мою концепцию. Пожалуйста, напишите ответ на него, и я приму то же самое

5. @DanielLangr разве ответ riquefr не делает недействительным все, что говорится в документации? «нет объявленных пользователем конструкторов»

Ответ №1:

Когда вы создаете новый fileJobPair , он будет использовать по умолчанию ваш пустой конструктор, поэтому он больше не будет доступен для завершения {} . Но вы можете добавить к нему новый конструктор, который получает 2 целых числа и привязывает их к соответствующим значениям, например:

 #include <iostream>
#include <map>

using namespace std;

struct fileJobPair {
        int file;
        int job;
        fileJobPair() {
            file = job = 0;
        }
        fileJobPair(int a, int b) {
            file = a;
            job = b;
        }
};

int main()
{
            map<int, fileJobPair> mp; 
            mp[1] = {10,10};
            mp[2] = {100, 200};
            mp[3] = {1000, 2000};
            for(int i =1;i<=3;i  )
            {
                cout<< mp[i].file <<" "<< mp[i].job<<endl;
             }
            return 0;
}
 

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

1. о, но как это работает, когда в документации говорится no user-declared constructors no user-provided constructors

2. Я не знаю о реализации на языке C , которая это позволяет, но я думаю, это потому, что теперь он знает, что вы можете использовать целочисленное значение 2 для инициализации структуры, когда вы используете пустой конструктор, у него нет возможности узнать это.

Ответ №2:

Согласно документации, вы можете использовать список инициализаторов только тогда, когда ваша структура / класс не содержит

  1. нет закрытых или защищенных прямых нестатических элементов данных
  2. нет объявленных пользователем конструкторов
  3. конструкторы, предоставленные пользователем, отсутствуют (разрешены явно установленные по умолчанию или удаленные конструкторы)
  4. нет пользовательских, унаследованных или явных конструкторов (разрешены явно установленные по умолчанию или удаленные конструкторы)
  5. нет объявленных пользователем или унаследованных конструкторов
  6. нет виртуальных, частных или защищенных базовых классов
  7. нет виртуальных функций-членов
  8. нет инициализаторов элементов по умолчанию

И в вашем случае ваша структура имеет конструктор, объявленный пользователем.

Как указано в комментариях OP, ответ @riqefr работает, а в документации указано иное.

Для этого вам нужно понять, что такое агрегат,

Агрегат — это массив или класс без объявленных пользователем конструкторов, без закрытых или защищенных нестатических элементов данных, без базовых классов и виртуальных функций.

Поэтому, когда вы добавили пользовательский конструктор в свою структуру, он больше не остается агрегатом.

Чтобы узнать больше о преимуществах aggregate по сравнению с вашими обычными классами. Пожалуйста, обратитесь https://www.educba.com/c-plus-plus-aggregation /