هل يمكنك استخدام الكلمات الرئيسية الفضائية لمنع التحويل التلقائي لمعلمات الطريقة؟

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

سؤال

أعلم أنه يمكنك استخدام الكلمة الرئيسية C ++ "صريحة" لمركيبات الفئات لمنع التحويل التلقائي للنوع. هل يمكنك استخدام هذا الأمر نفسه لمنع تحويل المعلمات لطريقة الفصل؟

لدي عضوان في الفصل ، أحدهما يأخذ منطقيًا كمعامل ، والآخر غير موقّع. عندما اتصلت بالوظيفة باستخدام int ، قام المترجم بتحويل المعلمة إلى منطقة ودعا الطريقة الخاطئة. أعلم في النهاية أنني سأستبدل منطقيًا ، لكن في الوقت الحالي لا أرغب في كسر الروتينات الأخرى حيث تم تطوير هذا الروتين الجديد.

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

المحلول

لا ، لا يمكنك استخدام صريح ، ولكن يمكنك القيام بذلك بدلاً من ذلك:

class ClassThatOnlyTakesBoolsAndUIntsAsArguments
{
public:
  void Method(bool arg1);
  void Method(unsigned int arg1);

  // Below just an example showing how to do the same thing with more arguments
  void MethodWithMoreParms(bool arg1, SomeType& arg2);
  void MethodWithMoreParms(unsigned int arg1, SomeType& arg2);

private:
  template<typename T>
  void Method(T arg1);

  // Below just an example showing how to do the same thing with more arguments
  template<typename T>
  void MethodWithMoreParms(T arg1, SomeType& arg2);
};

كرر هذا النمط لكل طريقة تأخذ bool أو unsigned int. لا تقدم تطبيقًا للنسخة المعمارية من الطريقة.

سيجبر هذا المستخدم دائمًا على استدعاء Bool أو إصدار INT غير الموقّع.

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

نصائح أخرى

رقم. explicit يمنع التحويل التلقائي بين فئات محددة ، بغض النظر عن السياق. وبالطبع لا يمكنك القيام بذلك للفصول المضمنة.

ما يلي عبارة عن غلاف أساسي للغاية يمكن استخدامه لإنشاء typedef قوي:

template <typename V, class D> 
class StrongType
{
public:
  inline explicit StrongType(V const &v)
  : m_v(v)
  {}

  inline operator V () const
  {
    return m_v;
  }

private:
  V m_v; // use V as "inner" type
};

class Tag1;
typedef StrongType<int, Tag1> Tag1Type;


void b1 (Tag1Type);

void b2 (int i)
{
  b1 (Tag1Type (i));
  b1 (i);                // Error
}

ميزة واحدة لطيفة من هذا النهج ، هي أنه يمكنك أيضًا التمييز بين المعلمات المختلفة مع نفس النوع. على سبيل المثال ، يمكن أن يكون لديك ما يلي:

class WidthTag;
typedef StrongType<int, WidthTag> Width;  
class HeightTag;
typedef StrongType<int, HeightTag> Height;  

void foo (Width width, Height height);

سيكون من الواضح لعملاء "فو" أي حجة هي.

شيء قد يناسبك هو استخدام القوالب. ما يلي يعرض وظيفة القالب foo<>() كونها متخصصة ل bool, unsigned int, ، و int. ال main() توضح الوظيفة كيف يتم حل المكالمات. لاحظ أن المكالمات التي تستخدم ثابتًا int التي لا تحدد اللاحقة التي ستحلها foo<int>(), ، لذلك ستحصل على خطأ في الاتصال foo( 1) إذا كنت لا تتخصص int. إذا كان هذا هو الحال ، فسيتعين على المتصلين الذين يستخدمون ثابت عدد صحيح حرفي استخدام "U" لاحقة للحصول على المكالمة لحل (قد يكون هذا هو السلوك الذي تريده).

وإلا عليك أن تتخصص int واستخدام "U" لاحقة أو يلقيها إلى unsigned int قبل نقله إلى unsigned int الإصدار (أو ربما تؤكد أن القيمة ليست سلبية ، إذا كان هذا هو ما تريده).

#include <stdio.h>

template <typename T>
void foo( T);

template <>
void foo<bool>( bool x)
{
    printf( "foo( bool)\n");
}


template <>
void foo<unsigned int>( unsigned int x)
{
    printf( "foo( unsigned int)\n");
}


template <>
void foo<int>( int x)
{
    printf( "foo( int)\n");
}



int main () 
{
    foo( true);
    foo( false);
    foo( static_cast<unsigned int>( 0));
    foo( 0U);
    foo( 1U);
    foo( 2U);
    foo( 0);
    foo( 1);
    foo( 2);
}

أعطى برنامج التحويل البرمجي تحذير "مكالمة غامضة" ، والذي سيكون كافيا.

كنت أقوم بتطوير TDD ولم أدرك أنني نسيت تنفيذ المكالمة المقابلة في الكائن الوهمي.

Bool هو int يقتصر على 0 أو 1. هذا هو المفهوم الكامل للعودة 0 ؛ ، هو نفس المنطق مثل قول عودة خطأ ؛ (لا تستخدم هذا في الكود رغم ذلك).

يمكنك أيضًا كتابة إصدار INT يدعو Bool One.

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