c ++用作模板参数

时间:2013-09-06 19:24:00

标签: c++ templates clang

我遇到了一些问题,可以通过以下代码恢复:

template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p)
{
  return fct(p.first);
}

int main(int argc, char *argv[])
{
  size_t val = 
    wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));

  return 0;
}

我正在使用clang编译器版本3.4,并且此代码无法使用以下错误进行编译

test-tmp.C:17:5: error: no matching function for call to 'wrapper'
    wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test-tmp.C:9:8: note: candidate template ignored: invalid explicitly-specified argument
      for template parameter 'fct'

我们的想法是在fct上包含一个哈希函数(模板参数std::pair),仅用于获取第一个字段。

dft_hash_fct是另一个模板,定义如下:

template <typename Key>
size_t dft_hash_fct(const Key & key)
{
  return SuperFastHash(key);
}

这个通用功能有效;它已被用于其他环境中。

所有这一切的目的是重用基于散列的集合(而不是映射)作为任何类型的项目的键映射。基于散列的ser在构造时间内接收散列函数。

感谢您的评论(David,Andrey和Kazark)

编辑:

嗯,我明白了,typename fct是一个类型,所以我无法处理指针函数;对不起琐事。不幸的是,我认为在包装器中传递函数作为参数的方法不起作用,因为哈希集需要一个带有以下签名的函数指针:

size_t (*the_function)(const Key & key);

因此,实现这一点,感谢您的观察,我将有问题的代码更改为:

template <typename Key, typename Data, size_t (*fct)(const Key & k)>
size_t wrapper(const std::pair<Key, Data> & p)
{
  return (*fct)(p.first);
}

int main(int argc, char *argv[])
{
  size_t val = 
    wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));

  return 0;
}

编译,链接和运行。另外,我把这一行:

size_t (*fct)(const std::pair<int, int>&) = 
    wrapper<int, int, dft_hash_fct<int>>;

cout <<  (*fct)(std::pair<int, int>(4,6)) << endl;

编译,链接ans运行。所以,我可以说编译器(当然根据语言)可以实例化函数并处理一个函数指针。

所以,之后我尝试修改我的原始代码,这是一个HAshSet的派生类,用于管理第一个字段散列的对。

我声明一些:

template <typename Key, typename Data>
class HashMap : public HashSet<std::pair<Key, Data>>
{
  ...
  HashMap(size_t (*function)(const Key & key))
    : HashSet<Key, Data>(wrapper<Key, Data, function>)
  {

  }

..
};

但编译(使用std = c ++ 11)失败并显示错误

./tpl_dynSetHash.H:353:7: error: no matching constructor for initialization of
      'HashSet<std::pair<unsigned long, long>>'
    : HashSet<std::pair<Key,Data>(
      ^
testDynSetHash.C:178:8: note: in instantiation of member function
      'HashMap<unsigned long, long>::HashMap' requested here
  HMap table; 

但是,如果我通过

将调用替换为基础构造函数
: HashSet<Key, Data>(wrapper<Key, Data, dft_hash_fct<Key>)

编译好。因此,我认为问题在于参数类型声明(但我不知道是什么)。

3 个答案:

答案 0 :(得分:4)

传递函数的标准习惯是将它们作为函数对象传递,例如

template <typename Key, typename Data, typename Fct>
size_t wrapper(const std::pair<Key, Data> & p, Fct fct)
{
  return fct(p.first);
}

然后使用:

调用包装器
int main(int argc, char *argv[])
{
  // no explicit template arguments required
  size_t val = 
    wrapper(std::pair<int,int>(5,9), &dft_hash_fct<int>);

  return 0;
}

在你的代码中,另一方面:

template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p)
{
  return fct(p.first);
}

typename fct为类型引入了别名。在此函数中,fct命名一个类型;因此fct(p.first)会创建fct类型的对象,并且此对象需要转换为size_t才能从wrapper返回。您也可以使用它,但您必须使用的类型必须如下所示:

struct dft_hash_fct_t
{
    size_t result;
    dft_hash_fct_t(int p) : result(SuperFashHash(p)) {}
    operator size_t() const { return result; }
};

这可能不是你想要的。

答案 1 :(得分:1)

中的模板声明
template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p)
{
  return fct(p.first);
}

将模板参数fct声明为类型,但是您尝试将函数指针传递给它。您可以像这样创建fct函数指针模板参数:

template <typename Key, typename Data, size_t(*fct)(const Key&)>
size_t wrapper(const std::pair<Key, Data> & p)
{
  return fct(p.first);
}

然而,更为惯用的方式是(如DyP所说)传递一个函数对象,以便该函数可以处理函数指针以及重载operator()的对象:

template <typename Key, typename Data, typename Fct>
size_t wrapper(const std::pair<Key, Data> & p, Fct fct)
{
  return fct(p.first);
}

然后在调用它时将函数作为参数传递

wrapper(std::pair<int,int>(5,9), dft_hash_fct<int>);

答案 2 :(得分:1)

您编写的代码在您的意图的上下文中毫无意义。您的fct模板参数是类型。这意味着

return fct(p.first);

函数式转换,而不是()运算符的应用程序(即它不是函数调用)。在您的代码中,您尝试将p.first转换为fct类型,然后尝试将该转换的结果返回为size_t。那是你的意图吗?我怀疑是的。最重要的是,您尝试将函数指针 value dft_hash_fct<int>作为fct的模板参数传递,即您传递,其中预计类型。你是怎么期望它起作用的?

您提供的说明似乎暗示您实际上想要从fct内部调用类型为wrapper的仿函数,而不是执行强制转换。为了做到这一点,你必须以某种方式获得仿函数。请再次记住,fct不是仿函数,它只是仿函数的类型

典型的方法是从外部传递函子,作为函数参数

template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p, fct f)
{
  return f(p.first);
}

现在,您可以将wrapper模板与基于类的仿函数以及普通函数一起使用

size_t val = wrapper(std::pair<int,int>(5,9), dft_hash_fct<int>);

请注意,dft_hash_fct<int>必须作为函数参数提供,而不是作为模板参数提供。 没有必要明确指定模板参数,因为它们将由编译器推导出来。