我很困惑如何在C ++中以通用方式实现某些东西。这有点令人费解,所以让我一步一步解释。
考虑这样的代码:
void a(int) {
// do something
}
void b(int) {
// something else
}
void function1() {
a(123);
a(456);
}
void function2() {
b(123);
b(456);
}
void test() {
function1();
function2();
}
很明显function1
和function2
做同样的事情,唯一不同的部分是内部函数。
因此,我想使function
通用以避免代码冗余。我可以使用函数指针或模板来完成它。我现在就选择后者。 我的想法是,它更好,因为编译器肯定能够内联函数 - 我是否正确?编译器是否可以通过函数指针进行内联调用?这是一个侧面问题。
好的,回到原点...带模板的解决方案:
void a(int) {
// do something
}
void b(int) {
// something else
}
template<void (*param)(int) >
void function() {
param(123);
param(456);
}
void test() {
function<a>();
function<b>();
}
一切都好。但是我遇到了一个问题:如果a
和b
本身就是泛型,我还可以这样做吗?
template<typename T>
void a(T t) {
// do something
}
template<typename T>
void b(T t) {
// something else
}
template< ...param... > // ???
void function() {
param<SomeType>(someobj);
param<AnotherType>(someotherobj);
}
void test() {
function<a>();
function<b>();
}
我知道模板参数可以是以下之一:
这些似乎都没有涵盖我的情况。我的主要问题是:我如何解决这个问题,即在最后一个例子中定义function()
?
(是的,在这个确切的情况下,函数指针似乎是一种解决方法 - 只要它们也可以内联 - 但我正在寻找这类问题的通用解决方案。)
答案 0 :(得分:27)
要使用模板解决此问题,您必须使用模板模板参数。 不幸的是,您无法将模板模板函数作为类型传递,因为它必须首先实例化。但是有一个虚拟结构的解决方法。这是一个例子:
template <typename T>
struct a {
static void foo (T = T ())
{
}
};
template <typename T>
struct b {
static void foo (T = T ())
{
}
};
struct SomeObj {};
struct SomeOtherObj {};
template <template <typename P> class T>
void function ()
{
T<SomeObj>::foo ();
T<SomeOtherObj>::foo ();
}
int main ()
{
function<a>();
function<b>();
}
答案 1 :(得分:0)
这是一种方式。它可能不是最好的,但它有效:
template <typename T, T param>
void function() {
param(123);
param(456);
}
void test()
{
function< void(*)(int), a<int> >(); // space at end necessary to compiler
function< void(*)(int), b<int> >(); // because the C++ grammar is ambiguous
}
它们是否被内联取决于编译器,但如果它们不是,我会感到很惊讶。
使用模板可能有一种棘手的方法,但这是我能想到的最简单的方法:
#define function(x) do { x<thing1>(obj1); x<thing2>(obj2) } while(0)
我知道,我知道,“宏是邪恶的,”等等等等。有用。如果function
需要比你的例子更复杂,你可能会遇到问题,但它比我能想到的任何事情都容易得多。
答案 2 :(得分:0)
使用C ++ 11中的lambda,您可以这样做:
template<typename T> void a(T t) { /* do something */}
template<typename T> void b(T t) { /* something else */ }
template <typename F>
void function(F&& f) {
f(someobj);
f(someotherobj);
}
void test() {
// For simple cases, auto&& is even probably auto or const auto&
function([](auto&& t){ a(t); });
function([](auto&& t){ b(t); });
// For perfect forwarding
function([](auto&& t){ a(std::forward<decltype(t)>(t)); });
function([](auto&& t){ b(std::forward<decltype(t)>(t)); });
}
如果编译器是通过函数指针进行的,编译器是否仍可以内联调用?
它们可以,但是确实更加复杂,并且与使用函子或模板相比,它们失败的可能性更高。
答案 3 :(得分:-2)
template < typename F >
void function(F f)
{
f(123);
}
void a(int x) { ... }
struct b { void operator() (int x) { ... } };
void outer()
{
function(&a);
function(b());
}