C++ عامل الحمولة الزائدة و التحويل الضمني
-
05-07-2019 - |
سؤال
لدي الدرجة التي تلخص بعض الحساب ، دعونا نقول نقطة ثابتة العمليات الحسابية.أنا أحب فكرة إثقال العوامل الحسابية ، لذلك أنا أكتب ما يلي:
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 )
{ ... }
واعتمادا على ما هو الرمز الموجود في وظائف، وهذا سوف تجميع فقط مع الأنواع التي أنت مع تحويل من.