[英]Differentiate typedefs
我正在為C庫編寫C ++抽象。 C庫有幾個用於標識遠程資源的ID的typedef:
typedef int color_id;
typedef int smell_id;
typedef int flavor_id;
// ...
color_id createColor( connection* );
void destroyColor( connection*, color_id );
// ...
所有這些typedef當然都是編譯器眼中的相同類型。 這對我來說是一個問題,因為我想重載函數和專門化模板來提供一個很好的C ++友好API:
// can't do the following since `color_id`, `smell_id` and `int` are the same
std::ostream& operator<<( std::ostream&, color_id );
std::ostream& operator<<( std::ostream&, smell_id );
void destroy( connection*, color_id );
void destroy( connection*, smell_id );
// no static check can prevent the following
smell_id smell = createSmell( connection );
destroyColor( connection, smell ); // it's a smell, not a color!
由於我不知道其他任何方式,我一直在考慮為每種C類型創建一個不同的包裝器類型。 但這條路看起來很粗糙......
那里有很多專門用於原始類型的代碼(例如std::hash
)。
有沒有辦法告訴編譯器類似“如果某些東西有int
,但不是我的包裝器,那么只需使用int
specialization”?
我是否應該為std::hash
類的東西編寫專門化? 那些不在std
類似模板結構怎么樣(例如boost,Qt等中的東西)?
我應該使用隱式或顯式構造函數和轉換運算符嗎? 明確的那些當然更安全,但它們會使與現有代碼和使用C API的第三方庫進行交互變得非常繁瑣。
我對那些已經去過那里的人的任何提示都持開放態度!
您最好的選擇是創建一個包裝類,但是使用模板我們可以編寫一個包裝類模板,並將它用於所有不同的ID,只需將它們分配給模板的不同實例即可。
template<class ID>
struct ID_wrapper
{
constexpr static auto name() -> decltype(ID::name()) {
return ID::name();
}
int value;
// Implicitly convertible to `int`, for C operability
operator int() const {
return value;
}
};
std::hash
(只需一次) 我們可以在ID
類中粘貼我們想要的任何特征,但我提供了name()
作為示例。 由於ID_Wrapper
是作為模板編寫的,因此只需對std::hash
和其他類進行一次專門化:
template<class ID>
class std::hash<ID_wrapper<ID>> : public std::hash<int>
{
public:
// I prefer using Base to typing out the actual base
using Base = std::hash<int>;
// Provide argument_type and result_type
using argument_type = int;
using result_type = std::size_t;
// Use the base class's constructor and function call operator
using Base::Base;
using Base::operator();
};
如果你願意,我們也可以專門化operator<<
,但是ID_wrapper
可以隱式轉換為int
:
template<class ID>
std::ostream& operator<<(std::ostream& stream, ID_Wrapper<ID> id) {
stream << '(' << ID_Wrapper<ID>::name() << ": " << id.value << ')';
return stream;
}
一旦我們有了這個,我們就為每個ID類型寫一個traits類!
struct ColorIDTraits {
constexpr static const char* name() {
return "color_id";
}
};
struct SmellIDTraits {
constexpr static const char* name() {
return "smell_id";
}
};
struct FlavorIDTraits {
constexpr static const char* name() {
return "flavor_id";
}
};
然后,我們可以typedef
的ID_wrapper:
using color_id = ID_wrapper<ColorIDTraits>;
using smell_id = ID_wrapper<SmellIDTraits>;
using flavor_id = ID_wrapper<FlavorIDTraits>;
使用BOOST_STRONG_TYPEDEF作為@MooingDuck的評論。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.