سؤال

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

في الرمز أدناه، يدير فئة المجمع كائنا مخصصا من كومة وتحويل ضمنيا إلى مرجع إلى هذا الكائن. هذا يسمح بمرور كائن Wrapper كوسيطة للكتابة الوظيفة (...) منذ التحويل الضمني يحدث.

ومع ذلك، فشل المحول البرمجي، عند محاولة حل المكالمة إلى المشغل << (...)، ما لم يتم إجراء ممثل صريح (تم التحقق من محاميل MSVC8.0 و Intel 9.1 و GCC 4.2.1).

لذلك، (1) لماذا يفشل التحويل الضمني في هذه الحالة؟ (2) هل يمكن أن تكون مرتبطة بحث تعتمد على الوسيطة؟ و (3) هل هناك أي شيء يمكن القيام به لجعل هذا العمل دون إيصال صريح؟

#include <fstream>

template <typename T>
class wrapper
{
    T* t;
  public:
    explicit wrapper(T * const p) : t(p) { }
    ~wrapper() { delete t; }
    operator T & () const { return *t; }
};

void write(std::ostream& os)
{
    os << "(1) Hello, world!\n";
}

int main()
{
    wrapper<std::ostream> file(new std::ofstream("test.txt"));

    write(file);
    static_cast<std::ostream&>( file ) << "(2) Hello, world!\n";
    // file << "(3) This line doesn't compile!\n";
}
هل كانت مفيدة؟

المحلول

فشل لأنك تحاول حل المشغل الخاص بك wrapper<T> الطبقة غير موجودة. إذا كنت تريد أن تعمل بدون الوكيل، فيمكنك تجميع شيء مثل هذا:

template<typename X> wrapper<T> &operator <<(X &param) const {
    return t << param;
}

لسوء الحظ، لا أعرف طريقة لحل نوع الإرجاع في وقت الترجمة. لحسن الحظ في معظم الحالات أنه نفس النوع مثل الكائن، بما في ذلك في هذه الحالة مع ostream.

تعديل: تعديل رمز حسب الاقتراح من Dash-Tom-Bang. تغيير نوع العودة إلى wrapper<T> &.

نصائح أخرى

المحول البرمجي ليس لديه سياق كاف لتحديد ذلك operator& سوف تجعل تحويل صحيح. لذلك، نعم، أعتقد أن هذا يرتبط بالبحث الذي تعتمد على الوسيطة: المحول البرمجي يبحث عن operator<< التي يمكن أن تقبل غيرconst wrapper<std::ostream> كمعلمة لها الأولى.

أعتقد أن المشكلة تتعلق بالحفاظ على بعض قيود وقت الترجمة. في مثالك، يجب أن يجد المحول البرمجي أولا الكل المشغل المحتمل <<. ثم، لكل منهم، يجب أن تحاول إذا كان يمكن تحويل كائنك تلقائيا (بشكل مباشر أو غير مباشر) لأي من أنواع كل مشغل << قادر على قبوله.

يمكن أن يكون هذا الاختبار معقدا حقا، وأعتقد أن هذا يقتصر على توفير وقت تجميع معقول.

بعد بعض الاختبارات، يحدد مثال أبسط حتى مصدر المشكلة. لا يمكن للمترجم استنتاج حجة القالب T في f2(const bar<T>&) أدناه من التحويل الضمني ل wrapper<bar<int> > ل bar<int>&.

template <typename T>
class wrapper
{
    T* t;
  public:
    explicit wrapper(T * const p) : t(p) { }
    ~wrapper() { delete t; }
    operator T & () const { return *t; }
};

class foo { };

template <typename T> class bar { };

void f1(const foo& s) { }
template <typename T> void f2(const bar<T>& s) { }
void f3(const bar<int>& s) { }

int main()
{
    wrapper<foo> s1(new foo());
    f1(s1);

    wrapper<bar<int> > s2(new bar<int>());
    //f2(s2); // FAILS
    f2<int>(s2); // OK
    f3(s2);
}

في المثال الأصلي، std::ostream في الواقع أ typedef للفئة القيب std::basic_ostream<..>, ، وينطبق نفس الوضع عند استدعاء الوظيفة القيب operator<<.

تحقق من توقيع مشغل الإدراج ... أعتقد أنهم يأخذون إشارة نوستريم غير كونست؟

مؤكد مع C ++ 03 معيار، توقيع شار * مشغل الإخراج هو:

template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);

التي تأخذ بالفعل مرجع غير الاتصال. لذلك لم يتطابق مشغل التحويل الخاص بك.

كما لوحظ في التعليق: هذا غير ذي صلة.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top