39

我只是对如何在 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>();
}

一切都好。但是我遇到了一个问题:如果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()在最后一个示例中定义?

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

4

4 回答 4

37

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

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>();
}
于 2011-01-15T00:42:11.953 回答
4

使用 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)); });
}

如果通过函数指针进行调用,编译器仍然可以内联调用吗?

它们可以,但它确实更复杂,并且它们可能比仿函数或模板更频繁地失败。

于 2019-05-31T17:21:55.957 回答
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需要比您的示例更复杂,您可能会遇到问题,但这比我想出的任何东西都容易。

于 2011-01-15T00:11:41.110 回答
-1
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());
}
于 2011-01-15T00:45:56.750 回答