مشغل محمّل [] على فئة القالب في C ++ مع إصدارات const / nonconst
-
27-09-2019 - |
سؤال
يا للعجب ، كان هذا لقبًا طويلًا.
ها هي مشكلتي. لقد حصلت على فئة قالب في C ++ وأنا أفرط في تحميل [] المشغل. لديّ نسخة من Const و Non-Const ، مع إرجاع الإصدار غير المشترك بالرجوع إليه بحيث يمكن تغيير العناصر في الفصل على ذلك:
myobject[1] = myvalue;
كل هذا يعمل حتى أستخدم منطقية كمعلمة قالب. إليك مثال كامل يوضح الخطأ:
#include <string>
#include <vector>
using namespace std;
template <class T>
class MyClass
{
private:
vector<T> _items;
public:
void add(T item)
{
_items.push_back(item);
}
const T operator[](int idx) const
{
return _items[idx];
}
T& operator[](int idx)
{
return _items[idx];
}
};
int main(int argc, char** argv)
{
MyClass<string> Test1; // Works
Test1.add("hi");
Test1.add("how are");
Test1[1] = "you?";
MyClass<int> Test2; // Also works
Test2.add(1);
Test2.add(2);
Test2[1] = 3;
MyClass<bool> Test3; // Works up until...
Test3.add(true);
Test3.add(true);
Test3[1] = false; // ...this point. :(
return 0;
}
الخطأ هو خطأ في المترجم والرسالة هي:
error: invalid initialization of non-const reference of type ‘bool&’ from a temporary of type ‘std::_Bit_reference’
لقد قرأت ووجدت أن STL تستخدم بعض أنواع البيانات المؤقتة ، لكنني لا أفهم سبب عملها مع كل شيء باستثناء منطق.
أي مساعدة في هذا سيكون موضع تقدير.
المحلول
لان vector<bool>
متخصص في STL ، ولا يفي بالفعل بمتطلبات الحاوية القياسية.
يتحدث Herb Sutter عن ذلك أكثر في مقال GOTW: http://www.gotw.ca/gotw/050.htm
نصائح أخرى
أ vector<bool>
ليست حاوية حقيقية. يحاول الرمز الخاص بك فعليًا إرجاع إشارة إلى بت واحد ، وهو أمر غير مسموح به. إذا قمت بتغيير الحاوية إلى أ deque
, ، أعتقد أنك ستحصل على السلوك الذي تتوقعه.
أ vector<bool>
لا يتم تنفيذه مثل جميع المتجهات الأخرى ، ولا يعمل مثلهم أيضًا. أنت أفضل حالًا ببساطة عدم استخدامه ، ولا تقلق إذا لم يتمكن الكود الخاص بك من التعامل مع العديد من خصوصياته - فهو في الغالب يعتبر أمرًا سيئًا ، يتم فرضه علينا من قِبل بعض أعضاء اللجنة القياسية غير المتفككين.
بعض التغييرات المونور في الفصل الخاص بك يجب إصلاحه.
template <class T>
class MyClass
{
private:
vector<T> _items;
public:
// This works better if you pass by const reference.
// This allows the compiler to form temorary objects and pass them to the method.
void add(T const& item)
{
_items.push_back(item);
}
// For the const version of operator[] you were returning by value.
// Normally I would have returned by const ref.
// In normal situations the result of operator[] is T& or T const&
// But in the case of vector<bool> it is special
// (because apparently we want to pack a bool vector)
// But technically the return type from vector is `reference` (not T&)
// so it you use that it should compensate for the odd behavior of vector<bool>
// Of course const version is `const_reference`
typename vector<T>::const_reference operator[](int idx) const
{
return _items[idx];
}
typename vector<T>::reference operator[](int idx)
{
return _items[idx];
}
};
كما تشير الإجابات الأخرى ، يتم توفير التخصص لتحسين تخصيص المساحة في حالة المتجه <OloL>.
ومع ذلك ، لا يزال بإمكانك جعل الكود الخاص بك صالحًا إذا قمت باستخدام Vector :: Reference بدلاً من T &. في الواقع ، من الممارسات الجيدة استخدام الحاوية :: المرجع عند الرجوع إلى البيانات التي تحتفظ بها حاوية STL.
T& operator[](int idx)
يصبح
typename vector<T>::reference operator[](int idx)
بالطبع هناك أيضًا typedef للإشارة إلى const:
const T operator[](int idx) const
ويصبح هذا (إزالة النسخة الإضافية غير المجدية)
typename vector<T>::const_reference operator[](int idx) const
سبب الخطأ هو ذلك vector<bool>
متخصص لحزم القيم المنطقية المخزنة داخل و vector<bool>::operator[]
إرجاع نوع من الوكيل الذي يتيح لك الوصول إلى القيمة.
لا أعتقد أن الحل هو إرجاع نفس النوع مثل vector<bool>::operator[]
لأنه بعد ذلك ، ستقوم بالنسخ على السلوك الخاص المؤسف إلى الحاوية الخاصة بك.
إذا كنت تريد الاستمرار في استخدام vector
كنوع أساسي ، أعتقد أنه يمكن تصحيح مشكلة Bool باستخدام أ vector<MyBool>
بدلا من ذلك MyClass
تم إنشاء مثيل له bool
.
قد يبدو هكذا:
#include <string>
#include <vector>
using namespace std;
namespace detail
{
struct FixForBool
{
bool value;
FixForBool(bool b): value(b) {}
operator bool&() { return value; }
operator const bool& () const { return value; }
};
template <class T>
struct FixForValueTypeSelection
{
typedef T type;
};
template <>
struct FixForValueTypeSelection<bool>
{
typedef FixForBool type;
};
}
template <class T>
class MyClass
{
private:
vector<typename detail::FixForValueTypeSelection<T>::type> _items;
public:
void add(T item)
{
_items.push_back(item);
}
const T operator[](int idx) const
{
return _items[idx];
}
T& operator[](int idx)
{
return _items[idx];
}
};
int main(int argc, char** argv)
{
MyClass<string> Test1; // Works
Test1.add("hi");
Test1.add("how are");
Test1[1] = "you?";
MyClass<int> Test2; // Also works
Test2.add(1);
Test2.add(2);
Test2[1] = 3;
MyClass<bool> Test3; // Works up until...
Test3.add(true);
Test3.add(true);
Test3[1] = false; // ...this point. :(
return 0;
}