簡體   English   中英

區分typedef

[英]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!
  • 如何區分這些ID,以利用類型安全和重載/專門化功能和類?

由於我不知道其他任何方式,我一直在考慮為每種C類型創建一個不同的包裝器類型。 但這條路看起來很粗糙......

  1. 那里有很多專門用於原始類型的代碼(例如std::hash )。
    有沒有辦法告訴編譯器類似“如果某些東西有int ,但不是我的包裝器,那么只需使用int specialization”?
    我是否應該為std::hash類的東西編寫專門化? 那些不在std類似模板結構怎么樣(例如boost,Qt等中的東西)?

  2. 我應該使用隱式或顯式構造函數和轉換運算符嗎? 明確的那些當然更安全,但它們會使與現有代碼和使用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(); 
};

用它的名字打印出一個ID

如果你願意,我們也可以專門化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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM