根据c++模板类型调用不同的C函数
Calling different C functions according to the C++ template type
我的问题如下:我有一个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++函数的全部目的是为了减少代码重复,而且"//从参数中获取类型T*的a,b, C"部分可能真的很长。
这个问题有一个简单的解决方案吗?
感谢格里格拉
定义重载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 );
}
某处你必须告诉编译器sadd
和add
是相关的
一种方法是trait类模板struct数学;
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 );
}
这样做的优点和缺点是把所有基于类型的重构放在一个地方。
另一种方法是为double
和float
创建具有重载的独立c++函数。这样做的优点和缺点是允许您的代码分布在多个位置。
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);
}
现在,假设所有函数共享相同的名称模式——double
为foo
, float
为sfoo
。在这种情况下,基于文本的代码生成可以用来缓解上述"编写过载"代码的一些问题。
这里唯一的问题是函数的签名可以变化。如果只有几个宏,简单的宏就可以了:
#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++ 11。(我认为以上应该在gcc 4.8和intel的最新版本中编译,而不是MSVC或clang 3.2)
现在您只需获取库中的每个函数,并创建一个由一堆单行样板文件组成的头文件:
namespace mymath {
MAKE_FUNCS( add )
MAKE_FUNCS( sub )
MAKE_FUNCS( chicken )
}
#undef MAKE_FUNCS
你可以用mymath::add
而不是add
或adds
来调用它。
这也可以通过其他形式的文本代码生成完成。
- 函数调用中参数的顺序重要吗
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 变量没有改变?通过向量的函数调用
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 模板函数调用
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 析构函数调用
- 成员函数调用和C++对象模型
- 使用共享指针的函数调用,其对象应为 const
- C++:编译时检查匹配的函数调用对?
- 函数调用C++中的参数太少
- 来自 DLL 的函数调用 [表观调用的括号前面的表达式必须具有(指向-)函数类型]
- 返回指向对象的指针的函数调用是否为 prvalue?
- C++ 如何重载 [] 运算符并进行函数调用
- 代码的效率. 转到和函数调用
- 是同一作用域的函数部分中的函数调用
- 如何封装一个函数,以便它只能由同一类中的一个其他函数调用?
- 类型擦除的std::function与虚拟函数调用的开销