6

我有以下代码:

template <typename T>
void f1( T t )
{
    std::cout << "f1( " << t << " ) called." << endl;
}

template <typename T>
void f2( T t )
{
    std::cout << "f2( " << t << " ) called." << endl;
}

template <typename F, typename T>
void call( F && f, T t )
{
    f( t );
}

template <typename T>
void foo( T t )
{
    call( f1<T>, t ); // Why is <T> necessary?
                      // f1(t) is a valid expression!
    call( f2<T>, t );
}

void bar()
{
    foo( 1 );
}

在函数中foo()我需要指定模板参数,即使f1(t)是一个有效的表达式。这有点破坏我的代码中的一些可能性。我的问题:

  1. 为什么我需要指定模板参数?
  2. 我该如何解决这个限制?(允许使用 C++11 或 C++14)。

(顺便说一句:我目前正在使用 Visual Studio 2010,如果我离开了,我会收到错误 C2896 <T>。)

4

6 回答 6

11

f1不是函数,而是模板。您不能将模板作为函数参数传递。

f1<T>是一个函数,所以可以传递。

于 2013-06-18T13:03:56.607 回答
8

1. 为什么需要指定模板参数?

嗯,f1不是一个对象,而是一个函数模板。您只能将对象传递给函数。

2. 我该如何解决这个限制?(允许使用 C++11 或 C++14)。

使用带有模板的对象operator()。只需将定义替换f1()

struct { template <typename T> void operator()( T t )
{
    std::cout << "f1( " << t << " ) called." << endl;
} } f1;

同样对于f2(). 在 C++14 中你可以写得更好

static const auto f1 = []( auto t )
{
    std::cout << "f1( " << t << " ) called." << endl;
};
于 2013-06-18T14:22:26.733 回答
3

您可以尝试将模板函数 f1 和 f2 包装在非模板类中并传递实例(甚至类型),例如

struct F1
{
  template <typename T>
  void operator()(T t) const
  {
    std::cout << "F1::operator()(" << t << ") called" << std::endl;
  }
};

struct F2
{
  template <typename T>
  void operator()(T t) const
  {
    std::cout << "F2::operator()(" << t << ") called" << std::endl;
  }
};

template <typename F, typename T>
void call(F && f, T t)
{
  f(t);
}

template <typename T>
void foo(T t)
{
  static const F1 f1;
  static const F2 f2;
  call(f1, t);
  call(f2, t);
}

void bar()
{
  foo(1);
}

产生输出:

F1::operator()(1) 调用

F2::operator()(1) 调用

于 2013-06-18T13:35:16.483 回答
1

f1(t)不是一个有效的表达式,因为没有 function f1。只有一个命名的模板可以在编译时生成f1一个函数。f1<T>

您所说的这种限制是编译时类型检查的直接后果。如果您在编译时知道 foo 的参数类型,则没有限制,因为您不能轻松添加它。如果你不知道参数的类型,你可能不得不使用派生类模型而不是模板驱动的想法。

于 2013-06-18T13:05:30.193 回答
1

有一种方法可以模拟传递函数模板(或重载集)作为一等值:通过将它们转换为函数对象来“具体化”它们。您的代码可以这样重写:

struct F1
{
  template <typename T>
  void operator ()( T t )
  {
    std::cout << "f1( " << t << " ) called." << endl;
  }
} f1;

struct F2
{
  template <typename T>
  void operator ()( T t )
  {
    std::cout << "f2( " << t << " ) called." << endl;
  }
} f2;

// Note that this function didn't change at all!
template <typename F, typename T>
void call( F && f, T t )
{
    f( t );
}
// Neither did this, expect that now you don't need the <T>
template <typename T>
void foo( T t )
{
    call( f1, t );
    call( f2, t );
}

void bar()
{
    foo( 1 );
    foo( 3.14 );
    foo( "Hello World" );
}
于 2013-06-18T15:49:05.960 回答
0

AngewUrzeit给出了为什么它不起作用的解释。

我试图提供的是解决您的问题的可能方法。但是,我无法准确判断这是否适合您的情况,因为 OP 提供的有关您的特定设计要求的信息有限。

第一步是将f1f2转换为模板仿函数类:

template <typename T>
class f1 {
public:
  void operator ()( T t ) {
      std::cout << "f1( " << t << " ) called." << std::endl;
  }
};

(对于 . 类似f2。)通过这种方式,您可以将f1(而不是f1<T>)作为模板模板参数传递call,现在以这种方式定义该参数:

template <template <typename> class F, typename T>
void call( T t )
{
    F<T> f;
    f( t );
}

请注意,这F是一个模板模板参数,它绑定到采用一个模板类型参数(例如f1)的模板类。

最后,foo变成了这样:

template <typename T>
void foo( T t )
{
    call<f1>( t );
    call<f2>( t );
}

bar像以前一样留下。

于 2013-06-18T13:29:22.763 回答