模板函数作为模板参数
Posted
技术标签:
【中文标题】模板函数作为模板参数【英文标题】:Template function as a template argument 【发布时间】:2011-01-15 00:01:14 【问题描述】:我只是对如何在 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()
?
(是的,在这种情况下,函数指针似乎是一种解决方法 - 只要它们也可以内联 - 但我正在寻找此类问题的通用解决方案)。 p>
【问题讨论】:
【参考方案1】:为了使用模板解决这个问题,您必须使用模板模板参数。 不幸的是,您不能将模板模板函数作为类型传递,因为它必须首先被实例化。但是有一个虚拟结构的解决方法。这是一个例子:
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>();
【讨论】:
不完全确定为什么这被否决了。这并不完全令人满意,但它解决了问题。 所以总结一下:可以内联调用的唯一解决方案是用仿函数替换函数?有点笨拙,但我认为完全可以接受。谢谢! 但我承认,当你说不可能内联按地址调用时,我感到非常惊讶......如果可以在编译时确定地址等于给定函数的地址,我希望编译器足够聪明。 :) 奇怪... 我用 g++ 4.5 运行过,结果相反:pastebin.com/eXbAyLPv @Kos:你的测试太简单了,gcc 足够聪明,可以优化简单的静态代码块。尝试一些更接近现实的东西。顺便说一句,同时指定-O3
和-Os
是没有意义的。如果您使用多个 -O 选项,无论有无级别编号,最后一个这样的选项是有效的。【参考方案2】:
使用 C++14 中的通用 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)); );
如果调用是通过函数指针进行的,编译器还能内联调用吗?
它们可以,但确实更复杂,而且它们可能比仿函数或模板更频繁地失败。
【讨论】:
通用 lambda 是 C++14 的一部分。 @mariusm:确实,措辞固定。【参考方案3】:这是一种方法。它可能不是最好的,但它确实有效:
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
需要比您的示例更复杂,您可能会遇到问题,但它比我想出的任何东西都容易。
【讨论】:
但是请注意function
会想要调用参数模板函数的不同实例化。
@Kos - #define
是不可能的吗?
嗯,它 是 一个“最后的手段”,它会起作用:),但编辑、调试、不能在命名空间中很不舒服......我' d 更愿意找到基于模板而不是基于预处理器的解决方案。【参考方案4】:
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());
【讨论】:
这不是 OP 想要的。 谢谢,但这与我描述的问题无关。在这种情况下,给定的function
调用仅使用参数函数/函子的 1 个实例化。请再次阅读问题。以上是关于模板函数作为模板参数的主要内容,如果未能解决你的问题,请参考以下文章