سؤال

لدي الدرجة التي تلخص بعض الحساب ، دعونا نقول نقطة ثابتة العمليات الحسابية.أنا أحب فكرة إثقال العوامل الحسابية ، لذلك أنا أكتب ما يلي:

class CFixed
{
   CFixed( int   );
   CFixed( float );
};

CFixed operator* ( const CFixed& a, const CFixed& b )
{ ... }

يعمل كل شيء.أستطيع أن أكتب 3 * CFixed(0) و CFixed(3) * 10.0 f.ولكن الآن أنا أدرك أنني يمكن تنفيذ المشغل* مع عدد صحيح المعامل أكثر فعالية بكثير.لذا الزائد:

CFixed operator* ( const CFixed& a, int b )
{ ... }
CFixed operator* ( int a, const CFixed& b )
{ ... }

أنه لا يزال يعمل ، ولكن الآن CFixed(0) * 10.0 و المكالمات طاقتها النسخة تحويل تطفو إلى int ( وأنا أتوقع أن تحويل تطفو إلى CFixed ).بالطبع لا يمكن أن تفرط تعويم الإصدارات أيضا ، ولكن يبدو اندماجي انفجار رمز بالنسبة لي.هل هناك أي حل (أو أنا تصميم صفي خطأ)?كيف يمكنني معرفة المترجم إلى دعوة طاقتها إصدار من المشغل* فقط مع رجات?

هل كانت مفيدة؟

المحلول

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

#include <cstdio>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_integral.hpp>

class CFixed
{
public:
   CFixed( int   ) {}
   CFixed( float ) {}
};

CFixed operator* ( const CFixed& a, const CFixed&  )
{ puts("General CFixed * CFixed"); return a; }

template <class T>
typename boost::enable_if<boost::is_integral<T>, CFixed>::type operator* ( const CFixed& a, T  )
{ puts("CFixed * [integer type]"); return a; }

template <class T>
typename boost::enable_if<boost::is_integral<T>, CFixed>::type operator* ( T , const CFixed& b )
{ puts("[integer type] * CFixed"); return b; }


int main()
{
    CFixed(0) * 10.0f;
    5 * CFixed(20.4f);
    3.2f * CFixed(10);
    CFixed(1) * 100u;
}

وبطبيعة الحال ، يمكن أيضا استخدام حالة مختلفة لجعل تلك الزائدة متاحة فقط إذا كان T=int: typename boost::enable_if<boost::is_same<T, int>, CFixed>::type ...

كما أن تصميم الطبقة ، ربما أنت يمكن أن تعتمد على قوالب أكثر.E. g, منشئ يمكن أن يكون القالب ، ومرة أخرى ، ينبغي أن كنت بحاجة إلى التمييز بين لا يتجزأ من الأنواع الحقيقية ، ينبغي أن يكون من الممكن استخدام هذه التقنية.

نصائح أخرى

ويجب الزائد مع نوع float كذلك. التحويل من int لنوع محدد من قبل المستخدم (CFixed) هو من أولوية أقل من المدمج في تحويل العائمة جزءا لا يتجزأ من float. وبالتالي فإن المترجم سيختار دائما وظيفة مع int، إلا إذا قمت بإضافة وظيفة مع float كذلك.

لمزيد من التفاصيل، وقراءة 13.3 جزء من C ++ 03 مستوى. يشعر بالألم.

ويبدو أنني قد فقدت المسار من ذلك أيضا. :-( UncleBens تقارير أن إضافة تعويم فقط لا يحل المشكلة، كإصدار مع double ينبغي أن يضاف أيضا. ولكن في أي حال إضافة عدة عوامل تتعلق أنواع المدمج في غير مملة، ولكن لا يؤدي إلى زيادة اندماجي.

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

وذلك قاعدة جيدة من التجربة تقول أنه كلما كنت تكتب المنشئات التي يمكن استدعاؤها مع وسيطة واحدة فقط (لاحظ أن هذا foo(int i, bool b = false) واحد يمكن أن يسمى مع وسيطة واحدة، أيضا، على الرغم من أنه يأخذ حجتين)، ل يجب جعل هذا explicit المنشئ، إلا إذا كنت تريد حقا التحويل الضمني لركلة في. لا تستخدم المنشئات explicit من قبل المجمع للتحويلات ضمنية.

وأنت سيكون لديك لتغيير صفك لهذه:

class CFixed
{
   explicit CFixed( int   );
   explicit CFixed( float );
};

ولقد وجدت أن هناك عدد قليل جدا من الاستثناءات لهذه القاعدة. (std::string::string(const char*) هو واحد مشهور نوعا ما.)

تحرير: أنا آسف، أنا غاب عن هذه النقطة حول عدم السماح تحويلات ضمنية من int إلى float.

والطريقة الوحيدة التي يمكنني رؤية لمنع هذا هي توفير المشغلين لfloat كذلك.

وماذا عن جعل تحويل صريحة ؟

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

ويمكنك تجنب وقوع انفجار في المشغل <> وظائف تكتب مع القوالب، ولكن:

template <class T>
CFixed operator* ( const CFixed& a, T b ) 
{ ... } 

template <class T>
CFixed operator* ( T a, const CFixed& b ) 
{ ... } 

واعتمادا على ما هو الرمز الموجود في وظائف، وهذا سوف تجميع فقط مع الأنواع التي أنت مع تحويل من.

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