C++ باستخدام Copy-ctor عند استخدام عامل التشغيل=() - كيف يعمل هذا بالضبط؟
-
21-12-2019 - |
سؤال
ما هي بالضبط قواعد C++ لتحويل مهمة عامل التشغيل=() إلى إنشاء؟مثل Foo foo = bar
سوف يستدعي في الواقع شريط قبول مُنشئ Foo كوسيطة، إذا كان موجودًا.لقد بحثت في Google عن كيفية عمل هذا ولكن لا يبدو أنني وجدت أي شيء.
أواجه مشكلة في معرفة سبب محاولة المهمة أدناه الحصول على مُنشئ ولكن عدم أخذ المُنشئ الصحيح بشكل واضح:HandlePtr (النوع والمورد).البناء باستخدام بناء جملة البناء الفعلي يعمل بشكل جيد، ولكن ليس مع مشغل المهمة.
الكود (تم تعديله بوضوح للإيجاز):
template< typename TYPE >
class HandlePtr {
public:
HandlePtr( void ) = default;
HandlePtr( HandlePtr< TYPE >& other ) = default;
HandlePtr( TYPE& resource ) {} // generally I would make this explicit, but for testing purposes I took it out
~HandlePtr( void ) = default;
public:
HandlePtr<TYPE>& operator=( TYPE& resource ) { return *this; }
HandlePtr<TYPE>& operator=( HandlePtr<TYPE>& other ) { return *this; }
};
int main ( void ) {
int x = 5;
HandlePtr< int > g( x ); // works
HandlePtr< int > i;i = x; // works
HandlePtr< int > h = x; // doesn't work
// also tried this just out of curiosity:
HandlePtr< int > h = HandlePtr< int >( x ); // also does not work
return 0;
}
الأخطاء:
shit.cpp: In function ‘int main()’:
try.cpp:19:24: error: no matching function for call to ‘HandlePtr<int>::HandlePtr(HandlePtr<int>)’
HandlePtr< int > h = x; // doesn't work
^
try.cpp:19:24: note: candidates are:
try.cpp:7:3: note: HandlePtr<TYPE>::HandlePtr(TYPE&) [with TYPE = int]
HandlePtr( TYPE& resource ) {} // generally I would make this explicit, but for testing purposes I took it out
^
try.cpp:7:3: note: no known conversion for argument 1 from ‘HandlePtr<int>’ to ‘int&’
try.cpp:6:3: note: HandlePtr<TYPE>::HandlePtr(HandlePtr<TYPE>&) [with TYPE = int]
HandlePtr( HandlePtr< TYPE >& other ) = default;
^
try.cpp:6:3: note: no known conversion for argument 1 from ‘HandlePtr<int>’ to ‘HandlePtr<int>&’
try.cpp:5:3: note: HandlePtr<TYPE>::HandlePtr() [with TYPE = int]
HandlePtr( void ) = default;
^
try.cpp:5:3: note: candidate expects 0 arguments, 1 provided
try.cpp:20:20: error: redeclaration of ‘HandlePtr<int> h’
HandlePtr< int > h = HandlePtr< int >( x ); // also does not work
^
try.cpp:19:20: error: ‘HandlePtr<int> h’ previously declared here
HandlePtr< int > h = x; // doesn't work
المحلول
أنت تتغاضى عن ذلك في تصريح:
T t = u;
هذا ليس عامل التعيين. t = u;
ليس تعبيرًا فرعيًا للإعلان.التعبير الوحيد هنا هو u
;ونتيجة تقييم التعبير u
يتم استخدامه كمهيئ للكائن t
يتم الإعلان عنها.
لو u
لديه نوع T
, ، ثم t
تم إنشاؤها من u
.
لو u
ليس لديه نوع T
, ، ثم u
يحتاج أولاً إلى تحويله إلى كتابة T
.هذا يخلق com.rvalue من النوع T
.
ليس لديك أي منشئين يقبلون قيمة r، لذا T t = u;
, ، ومثلها T t = T(u);
كلاهما يفشل.لكن، T t(u)
ينجح لأنه لم يتم إنشاء قيمة r؛القيمة u
يتم استخدامه كوسيطة للمنشئ T(U &)
.
مثال رمز مبسط:
struct T
{
T(int &);
T(T&);
T();
T &operator=(int &);
};
int main()
{
int x = 5;
T g(x); // OK, T(int &)
T g2(5); // fail, looks for T(int const &)
T i; // OK, T()
i = x; // OK, T::operator=(int&)
T h3 = i; // OK, T(T&)
T h1 = T(x); // fail, looks for T(T const &)
T h2 = x; // fail, identical to previous line
}
عادة يجب عليك استخدام const &
كمعلمة لمنشئي النسخ ومشغلي المهام؛ثم تصبح كل حالات "الفشل" هذه "موافق"، حيث يمكن ربط قيمة r بمرجع ثابت.