模板函数作为模板参数 我刚刚开始困惑,如何在C++中以通用的方式实现某些东西。这有点复杂,所以让我一步一步地解释

模板函数作为模板参数 我刚刚开始困惑,如何在C++中以通用的方式实现某些东西。这有点复杂,所以让我一步一步地解释,c++,templates,dry,generic-programming,C++,Templates,Dry,Generic Programming,考虑这样的代码: 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和functi

考虑这样的代码:

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
的作用是相同的,唯一不同的部分是内部函数

因此,我想使
函数
通用,以避免代码冗余。我可以使用函数指针或模板来完成。现在让我选择后者我的想法是这样更好,因为编译器肯定能够内联函数-我说的对吗?如果调用是通过函数指针进行的,编译器是否仍然可以内联调用?这是一个附带问题

好的,回到原点。。。具有模板的解决方案:

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型
  • 模板类型
  • 一种类型的值
这些似乎都不能掩盖我的处境。因此,我的主要问题是:如何解决这个问题,即在上一个示例中定义
function()

(是的,函数指针在这种情况下似乎是一种解决方法——只要它们也可以内联——但我正在寻找这类问题的通用解决方案)。

这里有一种方法。它可能不是最好的,但它是有效的:

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
}
模板
空函数(){
param(123);
param(456);
}
无效测试()
{
函数();//编译器所需的末尾空格
函数<空格(*)(int),b>();/ /因为C++语法不明确
}
它们是否内联取决于编译器,但如果它们没有内联,我会很惊讶

编辑:好的,我今天有点休息,错过了参数类型不同的部分。我的错

使用模板可能有一种棘手的方法,但这是我能想到的最简单的方法:

#define function(x) do { x<thing1>(obj1); x<thing2>(obj2) } while(0)
#定义函数(x)do{x(obj1);x(obj2)}while(0)

我知道,我知道,“宏是邪恶的,”诸如此类。它起作用了。如果
函数
需要比您的示例更复杂,您可能会遇到问题,但这比我能想到的任何东西都要简单。

为了解决模板的这个问题,您必须使用模板参数。 不幸的是,您不能将模板函数作为类型传递,因为必须首先实例化它。但是有一个虚拟结构的解决方案。以下是一个例子:

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>();
}
模板
结构a{
静态void foo(T=T())
{
}
};
模板
结构b{
静态void foo(T=T())
{
}
};
结构SomeObj{};
结构SomeOtherObj{};
模板
空洞函数()
{
T::foo();
T::foo();
}
int main()
{
函数();
函数();
}
模板
空洞函数(F)
{
f(123);
}
void a(int x){…}
结构b{void operator()(int x){…};
无效外()
{
功能&a;
函数(b());
}

使用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)); });
}
template void a(T){/*做点什么*/}
模板void b(T T){/*其他东西*/}
模板
无效函数(F&&F){
f(someobj);
f(其他对象j);
}
无效测试(){
//对于简单的情况,auto&&甚至可能是auto或const auto&
函数([](auto&t){a(t);});
函数([](auto&t){b(t);});
//完美转发
函数([](auto&t){a(std::forward(t));});
函数([](auto&t){b(std::forward(t));});
}
如果调用是通过函数指针进行的,编译器仍然可以内联调用吗


它们可以,但它确实更复杂,并且可能比使用functor或template失败的次数更多。

但是请注意,
函数
将要调用参数模板函数的不同实例化。@Kos-是不是
#define
不可能?好吧,这是一个“最后的办法”,它会起作用:),但是编辑、调试、不能在名称空间中是不舒服的。。。我更喜欢找到一个基于模板而不是基于预处理器的解决方案。不太清楚为什么这会被否决。这并不完全令人满意,但它解决了问题。所以总结一下:唯一可以内联调用的解决方案是用functor替换函数?有点笨拙,但我认为完全可以接受。谢谢但我承认,在你说不可能通过地址呼叫内联后,我非常惊讶。。。如果在编译时可以确定地址等于给定函数的地址,我希望编译器足够聪明。:)奇怪……我用g++4.5运行了一次,得到了相反的结果:@Kos:你的测试太简单了,gcc足够聪明,可以优化简单的静态代码块。尝试一些更接近现实的东西。顺便说一句,同时指定
-O3
-Os
是没有意义的。如果您使用多个-O选项,无论有无级别编号,最后一个这样的选项都是有效的。这不是OP想要的。谢谢,但这与我描述的问题无关。在这种情况下,给定的
函数
调用只使用一个参数函数/函子的实例化。请再读一遍这个问题。通用lambda是C++14的一部分。@mariusm:的确,措辞已经修正。
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());
}
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)); });
}