我正在围绕 C 库 libnetfilter_conntrack
创建一个 C++ 包装器,它使用函数 nfct_set_attr(...)
。它需要一个 enum
来定义要设置的属性的类型,以及一个 void*
来传递数据(根据属性不同而不同)。由于这是 C++,我想让它成为类型安全的,所以我需要为每个属性类型提供单独的函数。然而,为了提高兼容性,我创建了一个 enum class
,它定义了 libnetfilter_conntrack
中可用的所有属性类型。
我最初的想法是创建模板化的 set_attr(...)
函数,它根据需要设置的属性采用模板。例如:
template<attr_type, typename T> void set_attr(T); // designed to fail
template<> void set_attr<orig_ipv4_src, unsigned long>(unsigned long ip) {};
这种方法的优点是直接将 enum class
定义链接到函数,这可能会使逻辑更清晰一些。但我想到了另一个可能的选择,为每个属性使用单独的函数:
void set_orig_ipv4_src(unsigned long ip) {};
在函数内部,enum class
无论如何都会被使用(调用底层 C 例程),所以那些定义仍然存在。
以上两种方法哪个更有意义?使用模板版本是否存在任何固有问题?性能问题?
最佳答案
所写的模板方法确实有问题。考虑:
long ip = get_ip();
set_attr<orig_ipv4_src>(ip);
此代码无法编译。尽管 longs 可以转换为 unsigned longs,但我们还是回到了大概包含 static_assert(false) 的通用模板中。
有一种方法可以解决这个问题:
template<attrt ATTR>
struct attr_info {
typedef void argtype;
};
template<>
struct attr_info<orig_ipv4_src> {
typedef unsigned long argtype;
};
// etc.
template<attrt ATTR>
void set_attr(attr_info<ATTR>::argtype arg) {
// set the attr
}
这将很好地进行类型提升。如果需要,它还可以让您以其他方式获取此信息。
不过,尽管它很漂亮,但我不确定这种方法比单独的函数有任何实际优势。也就是说,我不确定这能实现的事情是任何人都想做的事情。新接触该项目的人需要做更多的工作才能理解。
我建议查看旧的 c 代码,看看是否有人使用非文字第一个参数调用此函数。如果是这样,请确保他们正在做的事情在新系统中是可行的。如果没有,可能会使用单独的函数。
关于c++ - 模板特化或分离函数的语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20116056/