لماذا لم يعد التهيئة التجميعية يعمل منذ C++ 20 إذا تم إنشاء مُنشئ بشكل افتراضي أو حذفه؟




c++17 backwards-compatibility (2)

أقوم بترحيل مشروع Visual Studio C ++ من VS2017 إلى VS2019.

تظهر لي رسالة خطأ الآن ، والتي لم تحدث من قبل ، والتي يمكن استنساخها مع هذه الأسطر القليلة من التعليمات البرمجية:

struct Foo
{
    Foo() = default;
    int bar;
};
auto test = Foo { 0 };

الخطأ هو

(6): الخطأ C2440: "التهيئة": لا يمكن التحويل من "قائمة مهيئ" إلى "فو"

(6): ملاحظة: لا يمكن لأي مُنشئ أن يأخذ نوع المصدر ، أو أن دقة التحميل الزائد للمنشئ كانت غامضة

يتم تصنيف المشروع مع /std:c++latest العلم. أنا استنساخه على godbolt . إذا قمت بالتبديل إلى /std:c++17 ، فسيتم تجميعه بشكل جيد كما كان من قبل.

حاولت ترجمة نفس الرمز مع -std=c++2a باستخدام -std=c++2a وحصلت على خطأ مشابه. أيضًا ، يؤدي إنشاء أو حذف المنشئات الأخرى إلى إنشاء هذا الخطأ.

على ما يبدو ، تمت إضافة بعض ميزات C ++ 20 الجديدة في VS2019 وأفترض أن أصل هذه المشكلة موصوف في https://en.cppreference.com/w/cpp/language/aggregate_initialization . هناك تقول أن المجموع يمكن أن يكون هيكلاً (من بين معايير أخرى)

  • لا يوجد أي مُنشئين مقدمين من قبل المستخدم أو موروثين أو صريحين (مُنشئون مُعطّلون بشكل صريح أو مُحذَّر صراحة) (منذ C ++ 17) (حتى C ++ 20)
  • لا يوجد أي مُنشئين مُعلَنَين أو موروثين (منذ C ++ 20)

لاحظ أنه تم إسقاط الجزء الموجود بين قوسين "المسموح به صراحة أو تم حذف المنشئات" وتغيير "المقدم من قبل المستخدم" إلى "تم التصريح عن المستخدم".

لذلك سؤالي الأول هو ، هل أنا على صواب في افتراض أن هذا التغيير في المعيار هو السبب في تجميع الشفرة من قبل ولكن لم يعد؟

بالطبع ، من السهل إصلاح هذا: فقط قم بإزالة المنشئات الافتراضية بشكل صريح.

ومع ذلك ، فقد قمت بالتخلي عن العديد من المنشئات وتعطيلها بشكل صريح في جميع المشاريع الخاصة بي لأنني وجدت أنه من المعتاد جعل الكود أكثر تعبيرًا بهذه الطريقة لأنه يؤدي ببساطة إلى حدوث مفاجآت أقل من المنشئين المفترضين أو المحذوفين ضمنيًا. مع هذا التغيير ، هذا لا يبدو مثل هذه العادة الجيدة بعد الآن ...

لذلك سؤالي الفعلي هو: ما هو السبب وراء هذا التغيير من C ++ 17 إلى C ++ 20؟ هل تم هذا التوافق مع الوراء عن قصد؟ هل كان هناك بعض المقايضات مثل "حسنًا ، لقد قطعنا التوافق إلى الوراء هنا ، ولكن من أجل الصالح الأكبر."؟ ما هو هذا الخير الأكبر؟


الملخص من P1008 ، الاقتراح الذي أدى إلى التغيير:

يتيح C ++ حاليًا تهيئة بعض الأنواع ذات المنشئات التي أعلن عنها المستخدم من خلال التهيئة التجميعية ، متجاوزة تلك المنشئات. والنتيجة هي الكود المفاجئ والمربك والعربات التي تجرها الدواب. تقترح هذه الورقة إصلاحًا يجعل دلالات التهيئة في لغة C ++ أكثر أمانًا وتناسقًا وأسهل في التدريس. نناقش أيضًا التغييرات العاجلة التي يقدمها هذا الإصلاح.

أحد الأمثلة التي يقدمونها هو التالي.

struct X {
  int i{4};
  X() = default;
};

int main() {
  X x1(3); // ill-formed - no matching c’tor
  X x2{3}; // compiles!
}

بالنسبة لي ، من الواضح تمامًا أن التغييرات المقترحة تستحق التعارض مع الإصدارات السابقة. وبالفعل ، لا يبدو أنه من الممارسات الجيدة بعد الآن = default إنشاء التجميع الافتراضي الافتراضي.


في الواقع ، تناولت MSDN مخاوفك في المستند أدناه:

تعديل مواصفات النوع الكلي

في Visual Studio 2019 ، تحت / std: c ++ الأحدث ، لا تعتبر فئة مع أي مُنشئ مُعلَن من قِبل المستخدم (على سبيل المثال ، بما في ذلك مُنشئ مُعلَن = default أو = delete) تجميعًا. في السابق ، كان منشئي المحتوى المقدمين من قِبل المستخدم فقط هم الذين سيؤهلون الفصل من التجميع. يضع هذا التغيير قيودًا إضافية على كيفية تهيئة هذه الأنواع.







c++20