根据C ++模板类型调用不同的C函数(Calling different C functions a

2019-10-18 01:13发布

我的问题是这样的:我有包含根据该数据类型它们与例如,工作的每个函数的几个版本的C库:

void add(double *a, double *b, double *c);

void sadd(float *a, float *b, float *c);

现在,具有外部C ++模板功能,我希望能够做这样的事情:

template<class T>
void myfunc(/*params*/)
{
 // Obtain a,b,c of type T* from params

/*
 If T is double call add(a,b,c);
 else if T is float call sadd(a,b,c).
*/ 
}

据我所知,它可以通过像专门的模板函数来完成:

template<>
void myfunc<double>(/*params*/)
{
  // Obtain a,b,c of type double* from params
  add(a,b,c);
}

等等,但它不是一个真正的选择,因为引入模板C ++函数的整点是减少码重复和“//获取的A,B,C从PARAMS类型T *的”部分可以是很长的。

请问这个问题有一个简单的解决方案吗?

谢谢

兹德涅克

Answer 1:

限定重载C ++代理:

inline void forward_add(double *a, double *b, double *c) { add( a, b, c ); }
inline void forward_add(float *a, float *b, float *c) { sadd( a, b, c ); }

template<class T>
void myfunc(/*params*/)
{
   // Obtain a,b,c of type T* from params
   forward_add( a, b, c );
}


Answer 2:

某处你必须告诉编译器saddadd有关系。

一种方法是一个traits类模板结构数学;

template<>
struct math<double> {
  static void add(double *a, double *b, double *c) {
    return ::add(a, b, c);
  }
};
template<>
struct math<float> {
  static void add(float*a, float*b, float*c) {
    return ::sadd(a, b, c);
  }
};

在您使用它,如:

template<class T>
void myfunc(/*params*/)
{
  // Obtain a,b,c of type T* from params

  math<T>::add( a, b, c );
}

这具有优势,并把所有的基于类型的重构为一个点的缺点。

另一种方法是为创建具有重载自由站立C ++函数doublefloat 。 这样做的好处,并蔓延让你的代码的缺点在多个点。

void math_add( double* a, double* b, double* c ) {
  add(a,b,c);
}
void math_add( float* a, float* b, float* c ) {
  sadd(a,b,c);
}

现在,假设你的所有功能共享名称相同的模式- foodoublesfoofloat 。 在这种情况下,基于文本代码生成可用于缓解一些上述“写入过载”的代码。

这里唯一的问题是,该函数的签名可以改变。 如果只有极少数,简单的宏将工作:

#define MAKE_FUNCS( f ) \
  void CONCAT( math_, f ) ( double* a, double* b, double * c ) { \
    f ( a, b, c ); \
  } \
  void CONCAT( math_, f ) ( float* a, float* b, float* c ) { \
    CONCAT( f, s ) ( a, b, c ); \
  }

然后就垃圾邮件进入MAKE_FUNCS为库中您要克隆这样每个功能。

(在许多)一种缺点是,它仅支持一组固定的签名。 我们可以通过完善的转发,一个C ++ 11的技术解决这个问题:

#define MAKE_FUNCS( f ) \
  template< typename... Args >\
  auto f ( Args&&... args ) \
    -> decltype(::f ( std::forward<Args>(args)... )) \
  { \
    ::f ( std::forward<Args>(args)... ); \
  } \
  template< typename... Args >\
  auto f ( Args&&... args ) \
    -> decltype(:: CONCAT( f, s ) ( std::forward<Args>(args)... )) \
  { \
    :: CONCAT( f, s ) ( std::forward<Args>(args)... ); \
  }

但这种运行到SFINAE和相同的签名问题。 您可以通过明确表达SFINAE解决这个问题:

#include <utility>
#include <type_traits>
#include <cstddef>
#include <iostream>

#define CONCAT2( a, b ) a##b
#define CONCAT( a, b ) CONCAT2(a,b)

// SFINAE helper boilerplate:
template<typename T> struct is_type:std::true_type {};
template<std::size_t n> struct secret_enum { enum class type {}; };
template<bool b, std::size_t n>
using EnableIf = typename std::enable_if< b, typename secret_enum<n>::type >::type;

// Macro that takes a srcF name and a dstF name and an integer N and
// forwards arguments matching dstF's signature.  An integer N must be
// passed in with a distinct value for each srcF of the same name:
#define FORWARD_FUNC( srcF, dstF, N ) \
template< typename... Args, \
  EnableIf< is_type< \
    decltype( dstF ( std::forward<Args>(std::declval<Args>())... )) \
  >::value , N >... > \
auto srcF ( Args&&... args ) \
  -> decltype(dstF ( std::forward<Args>(args)... )) \
{ \
  dstF ( std::forward<Args>(args)... ); \
}

#define MAKE_FUNCS( f ) \
  FORWARD_FUNC( f, ::f, 0 ) \
  FORWARD_FUNC( f, :: CONCAT( f, s ), 1 )

void add( double* a, double* b, double* c) {*a = *b+*c;}
void adds( float* a, float* b, float* c) {*a = *b+*c;}
namespace math {
  MAKE_FUNCS(add)
}
int main() {
  double a, b = 2, c = 3;
  float af, bf = 3, cf = 5;
  math::add( &a, &b, &c );
  math::add( &af, &bf, &cf );
  std::cout << a << "=" << b << "+" << c << "\n";
  std::cout << af << "=" << bf << "+" << cf << "\n";
}

但你可以看到,这是越来越漂亮钝,有没有可以在这一点上处理这个级别C ++ 11isms的许多编译器。 (我觉得上面应该在GCC 4.8编译和英特尔最新的,但不是MSVC或铛3.2)

现在,你只需拿在库中的每个功能,包括做一堆单行样板的头文件:

namespace mymath {
  MAKE_FUNCS( add )
  MAKE_FUNCS( sub )
  MAKE_FUNCS( chicken )
}
#undef MAKE_FUNCS

然后您可以说调用mymath::add ,而不是addadds

这也可以通过其他形式的文字代码生成的完成。



文章来源: Calling different C functions according to the C++ template type