المسند "الذكي" C++ لخوارزمية stl
سؤال
أحتاج إلى تصميم مسند لخوارزميات stl مثل find_if وcount_if.
namespace lib
{
struct Finder
{
Finder( const std::string& name ):
name_( name )
{
}
template< typename TElement >
bool operator( const TElement& element )
{
return element.isPresent( name_ );
}
/* template< typename TElement >
bool operator( const TElement& element )
{
const Data& data = element.getData();
return data.isPresent( name_ );
}*/
};
}
لكنني أحتاج إلى عوامل تشغيل مختلفة () وفقًا لوجود بعض الأساليب المحددة في TElement.كما لو كانت تحتوي على "getData" أود التحقق من تلك البيانات وإذا لم تكن كذلك فسأقوم ببعض الإجراءات الأخرى.
أنا على علم بـ SFINAE.لكن ليس لدي دفعة::حول المشروع.لذلك إما أن يكون هناك بعض التنفيذ السهل للقالب "has_method" أو أنك تعرف بعض حلول التصميم الأخرى.
لا يمكنني الإشارة إلى أنواع محددة والتحميل الزائد ببساطة لأنني أرغب في وضع هذا المسند على إحدى مكتبة المشروع، التي لا تعرف شيئًا عن تلك الفئات المحددة باستخدام طريقة "getData".
الحل مع سمات الفصل جيد بقدر ما لا توجد مساحات أسماء.الباحث عن المسند في مساحة الاسم "lib" والفئة التي تحتوي على "getData" موجودة في مساحة الاسم "البرنامج".
شكرًا.
المحلول
لماذا استخدام قالب mathods لفي كل شيء؟ مجرد استخدام فئة معينة التي تريد وضعها على أساس أو الفئات الأساسية المشتركة إذا كان هناك الكثير من أنواع الطبقة.
ومنها مثلا.
struct Finder
{
Finder( const std::string& name ):
name_( name )
{
}
bool operator( const IsPresentBaseClass& element )
{
return element.isPresent( name_ );
}
bool operator( const GetDataBaseClass& element )
{
const Data& data = element.getData();
return data.isPresent( name_ );
}
};
إذا هذا النمط يحدث كثيرا مع أنواع فئة مختلفة وكنت تعرف أنواع قبل استخدام المسند هل يمكن أن القالب المسند نفسها.
ومنها مثلا.
template<class T1, class T2>
struct Finder
{
Finder( const std::string& name ):
name_( name )
{
}
bool operator( const T1& element )
{
return element.isPresent( name_ );
}
bool operator( const T2& element )
{
const Data& data = element.getData();
return data.isPresent( name_ );
}
};
وأو نهج آخر هل يمكن استخدام هو استخدام نوع من الصفات فئة لاستيعاب معلومات.
ومنها مثلا.
struct UseIsPresent
{
template<class T>
static bool CompareElement( const T& element, const std::string& name )
{
return element.isPresent( name );
}
};
struct UseGetData
{
template<class T>
static bool CompareElement( const T& element, const std::string& name )
{
const Data& data = element.getData();
return data.isPresent( name );
}
};
// default to using the isPresent method
template <class T>
struct FinderTraits
{
typedef UseIsPresent FinderMethodType;
};
// either list the classes that use GetData method
// or use a common base class type, e.g. UseGetData
template <>
struct FinderTraits<UseGetData>
{
typedef UseGetData FinderMethodType;
};
struct Finder
{
Finder( const std::string& name )
: name_( name )
{
}
template<class T>
bool operator()( const T& element )
{
return FinderTraits<T>::FinderMethodType::CompareElement<T>(element, name_);
}
std::string name_;
};
وسلبيات كل من هذه الأساليب هي أنه عند نقطة معينة أنت بحاجة إلى معرفة أنواع لتكون قادرة على تقسيمها إلى الطريقة التي يجب استخدامها.
نصائح أخرى
ويمكنك إلقاء نظرة على موقع VELDHUIZEN لو> للقالب switch
. ربما يمكنك استخدام هذا لاختيار المشغل بالضبط؟
اجعل أنواعك مستمدة من "أنواع الوظائف" (على سبيل المثال النوع "has_function1") التي ستعمل كواجهات جافا ولديك فرصة، لأنه يمكن استخدام SFINAE لاختبار ما إذا كان من الممكن تحويل نوع واحد إلى نوع آخر.
إذا كنت مهتمًا، فيمكنني أن أبحث في الأمر وأعطيك إجابة أكثر تفصيلاً.
يحرر :أعلم أنك قلت أنه ليس لديك مكتبات Boost متاحة، ولكن هل هناك أي شيء يمنعك من الحصول على الملفات القليلة المطلوبة للحصول على Boost::is_convertible Work ؟لن يكون هناك أي شيء على وجه الخصوص لتجميع!
والدافع ليست سحرية، باستخدام SFINAE اضحة إلى حد ما:
template< typename TElement >
bool operator( const TElement& element, ... )
{
return element.isPresent( name_ );
}
template< typename TElement >
bool operator( const TElement& element, const Data& data = element.getData())
{
return data.isPresent( name_ );
}
وSFINAE سيتم إزالة الزائد الثاني اذا لم تجميع. وقرار الزائد اختيار الثاني، إذا لم تجمع منذ ... هو أسوأ مباراة.