模板函数作为模板参数

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();

很容易注意到function1function2 的作用相同,唯一不同的部分是内部函数。

因此,我想将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>();

一切正常。但我遇到了一个问题:如果 ab 本身是泛型,我还能这样做吗?

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 个实例化。请再次阅读问题。

以上是关于模板函数作为模板参数的主要内容,如果未能解决你的问题,请参考以下文章

模板函数作为模板参数

使用模板化函数作为模板参数

函数接受函数作为模板类型的参数

如何派生抽象模板类,模板类型作为函数参数 (C++11)

作为默认模板参数的具体函数

如何将构造函数(可变参数)作为模板参数传递?