简体   繁体   English

在C ++中使用类型作为枚举包装C-API

[英]Wrap C-API with types as enums in C++

Currently, I write a C++ Wrapper for a C-Library which acts as the driver for a camera. 目前,我为C-Library编写了一个C ++ Wrapper,它充当了摄像头的驱动程序。 The camera can be set with properties that can be float , bool or int . 可以使用floatboolint属性设置摄像机。 Each property has an ID which is member of an enum PropId . 每个属性都有一个ID,它是enum PropId成员。 For each of these types, there is an attribute information struct , a function to get and set the value: 对于每种类型,都有一个属性信息struct ,一个获取和设置值的函数:

GetPropertyAttribsI
GetPropertyAttribsB
GetPropertyAttribsF
PropAttribsI
PropAttribsF
PropAttribsB
SetPropertyValueI
SetPropertyValueF
SetPropertyValueB

My problem is now that I want to write code to: 我现在的问题是我想编写代码:

  1. Check whether the property value to set is in bounds , else sets it to default. 检查要设置的属性值是否在边界内 ,否则将其设置为默认值。 The bounds and default can be looked up in the PropAttribs struct , which can be initialized with the respective GetPropertyAttribs function. 可以在PropAttribs struct查找边界和默认值,该PropAttribs struct可以使用相应的GetPropertyAttribs函数进行初始化。
  2. Set the property with the corresponding SetPropertyValue(I,B,F) 使用相应的SetPropertyValue(I,B,F) 设置属性

I can look up the type of the property, it is in an enum (PROP_TYPE_INT, PROP_TYPE_FLOAT, PROP_TYPE_BOOL) . 我可以查找属性的类型,它位于enum (PROP_TYPE_INT, PROP_TYPE_FLOAT, PROP_TYPE_BOOL)

So what I want is a function : 所以我想要的是一个功能

checkAndSanitizeProperty(T& value, PropId property)

that checks whether a given property is in bounds, else sets it to default. 检查给定属性是否在边界内,否则将其设置为默认值。

The skeleton would be the following, but I do not know how I can make it so generic with template parameters that it is usable for bool and float without copying. 骨架将是以下,但我不知道如何使用模板参数使它如此通用,它可用于boolfloat而不复制。 The function for setting parameters is very similar to that, and should have the same solution if any is found. 设置参数的功能与此非常相似,如果找到任何参数,则应该具有相同的解决方案。

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;
  }
}

What gets on my nerves is that I have to repeat a lot of code, so I search for a cleaner solution. 让我紧张的是,我必须重复很多代码,所以我寻找一个更清洁的解决方案。 I do not mainly use C++, so I haven't got too much experience with template magic or C++ idioms. 我主要不使用C ++,所以我对模板魔术或C ++习语没有太多经验。

Macro hackery. 宏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); \
  };

takes a base structure name like VRmPropAttribs and makes it so that VRmPropAttribs_t<int> is VRmPropAttribsI . 采用类似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)...); \
    } \
  }; \

etc for B and F. 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)...); }

which defines a function template named X that, when passed int , calls XI with the same arguments. 它定义了一个名为X的函数模板,当传递给int ,它使用相同的参数调用XI

Now, this doesn't handle your %d format strings and the like, but you can do things like: 现在,这不会处理你的%d格式字符串之类,但你可以做以下事情:

VRmPropAttribs attribs; VRmPropAttribs attribs; VRmUsbCamGetPropertyAttribs(device, property, &attribs); VRmUsbCamGetPropertyAttribs(设备,财产和属性); after you use the above macros. 使用上面的宏后。 And once you can do the above, you can replace int with T and make your method a template method. 一旦你可以做到这一点,你可以用T替换int并使你的方法成为模板方法。

You'll also want a better version of VRM_PROP_TYPE_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>
{};

etc lets you do: 等你可以做到:

vrm_prop_type<T>{} != propInfo.m_type

checks. 检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM