2015-08-28 74 views
3

當前,我爲C-Library編寫了一個C++包裝器,該C-Library作爲相機的驅動程序。相機可以設置屬性,可以是float,boolint。每個酒店都有一個身份證,該證件是enum PropId的成員。對於這些類型的,還有一個屬性信息struct,一個函數來獲取和設置值:將類型作爲枚舉類型的C-API封裝在C++中

GetPropertyAttribsI 
GetPropertyAttribsB 
GetPropertyAttribsF 
PropAttribsI 
PropAttribsF 
PropAttribsB 
SetPropertyValueI 
SetPropertyValueF 
SetPropertyValueB 

我的問題是,現在我要編寫代碼:

  1. 檢查是否要設置的屬性值在範圍內,否則將其設置爲默認值。邊界和默認值可以在PropAttribs struct中查找,可以使用相應的GetPropertyAttribs函數進行初始化。
  2. 設置屬性與相應SetPropertyValue(I,B,F)

我可以看一下屬性的類型,它是在enum (PROP_TYPE_INT, PROP_TYPE_FLOAT, PROP_TYPE_BOOL)

所以,我要的是一個功能

checkAndSanitizeProperty(T& value, PropId property) 

,檢查一個給定的屬性是否超出範圍,否則將其設置爲默認值。

框架將如下,但我不知道如何使它與模板參數非常通用,它可用於boolfloat而無需複製。設置參數的功能與此非常相似,並且如果找到任何參數,應該有相同的解決方案。

void CameraHandle::checkAndSanitizeProperty(int& value, VRmPropId property, std::string name) { 
    VRmPropInfo propInfo; 
    VRM_CHECK(VRmUsbCamGetPropertyInfo(device, property, &propInfo)); 

    if (VRM_PROP_TYPE_INT != propInfo.m_type) { 
    ROS_ERROR("Invalid type of property!"); 
    } 

    VRmPropAttribsI attribs; 
    VRmUsbCamGetPropertyAttribsI(device, property, &attribs); 
    if (value < attribs.m_min || value > attribs.m_max) { 
    ROS_WARN("Invalid value for parameter %s, has to be in [%d,%d], but was: %d", 
      name.c_str(), 
      attribs.m_min, 
      attribs.m_max, 
      value); 

    ROS_WARN("Default will be used for %s: %d", name.c_str(), attribs.m_default); 
    value = attribs.m_default; 
    } 
} 

對我的神經有什麼讓我不得不重複許多代碼,所以我尋找一個更乾淨的解決方案。我不主要使用C++,所以我對模板魔法或C++習慣用法沒有太多的經驗。

回答

2

宏hackery。

#define CONCAT2(A, B) A##B 
#define CONCAT(A,B) CONCAT2(A,B) 

#define MAP_STRUCT(X) \ 
    template<class T> struct X; \ 
    template<class T> using CONCAT(X,_t) = typename X<T>::type; \ 
    template<> struct X<int> { \ 
    using type= CONCAT(X, I); \ 
    }; \ 
    template<> struct X<float> { \ 
    using type= CONCAT(X, F); \ 
    }; \ 
    template<> struct X<bool> { \ 
    using type= CONCAT(X, B); \ 
    }; 

需要一個底座結構名稱等VRmPropAttribs並使得使得VRmPropAttribs_t<int>VRmPropAttribsI

#define CALL(X) CONCAT(call_, X) 
#define MAP_FUNC_CALL(X) \ 
    template<class T> \ 
    struct CALL(X); \ 
    template<> struct CALL(X)<int> { \ 
    template<class...Args> \ 
    auto operator()(Args&&...args)const \ 
    -> decltype(CONCAT(X,I)(std::declval<Args>()...)) { \ 
     return CONCAT(X,I)(std::forward<Args>(args)...); \ 
    } \ 
    }; \ 

對於B等,並F.

#define MAP_FUNC(X) \ 
    MAP_FUNC_CALL(X) \ 
    template<class T, class...Args> \ 
    auto X(Args&&...args) \ 
    -> typename std::result_of< CALL(X)(Args...) > \ 
    { return CALL(X)<T>{}(std::forward<Args>(args)...); } 

它定義了一個名爲X一個函數模板,通過int時,調用XI具有相同的參數。現在

,這不處理你%d格式字符串之類的,但你可以做這樣的事情:

VRmPropAttribs attribs; VRmUsbCamGetPropertyAttribs(device,property,& attribs);在使用上述宏之後使用 。一旦你可以做到上述,你可以用T替換int,並使你的方法成爲模板方法。

您還需要一個更好的版本的VRM_PROP_TYPE_INT

template<class T> struct vrm_prop_type{}; 
template<> struct vrm_prop_type<int>: 
    std::integral_constant<int, VRM_PROP_TYPE_INT> 
{}; 

等讓你做:

vrm_prop_type<T>{} != propInfo.m_type 

檢查。

+0

這看起來很酷。不幸的是,我認爲它比簡單地複製每種類型的函數的可讀性和可維護性都差。 – reindeer

+0

@reindeer如果您只有1或2個函數,那麼編寫手工生成的宏比使用上述宏更好。最後你會得到一個統一的商業邏輯功能,這很好。 – Yakk