مشغل محمّل [] على فئة القالب في C ++ مع إصدارات const / nonconst

StackOverflow https://stackoverflow.com/questions/3458856

سؤال

يا للعجب ، كان هذا لقبًا طويلًا.

ها هي مشكلتي. لقد حصلت على فئة قالب في 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;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top