简体   繁体   English

c ++用作模板参数

[英]c++ functions as template arguments

I'm experiencing some problems which can be resumed by the following piece of code: 我遇到了一些可以通过以下代码恢复的问题:

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;
}

I'm using clang compiler version 3.4 and this code does not compile with the following error 我正在使用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'

The idea is to wrap a hash function (the template parameter fct ) on std::pair for only taking the first field. 这个想法是将散列函数(模板参数fct )包装在std::pair ,仅用于第一个字段。

dft_hash_fct is another template defines as follows: dft_hash_fct是另一个模板,定义如下:

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

This generic function works; 该通用功能有效; it has been used in other contexts. 它已在其他情况下使用。

The purpose of all this is to reuse a hash based set (not map) as a map of keys to items of any type. 所有这一切的目的是将基于哈希的集合(而不是映射)复用为任何类型的项的键的映射。 The hash based ser receives a hash function in construction time. 基于散列的ser在构造时间接收散列函数。

Thanks for your comments (David, Andrey and Kazark) 感谢您的评论(David,Andrey和Kazark)

Edited: 编辑:

Well, I see, typename fct is a type, so I cannot handle as a pointer function; 好吧,我知道,typename fct是一个类型,因此我不能作为指针函数来处理; sorry for the trivia. 对不起,琐事。 Unfortunately, I believe that the approach of passing the function as parameter in the wrapper does not work, because the hash set expects a function pointer with the following signature: 不幸的是,我认为在包装器中将函数作为参数传递的方法不起作用,因为哈希集需要具有以下签名的函数指针:

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

So, realizing this, thanks to your observations, I changed the code in question to: 因此,意识到这一点,由于您的观察,我将相关代码更改为:

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;
}

that compiles, links and runs. 进行编译,链接和运行。 In addition, I put this line: 另外,我把这一行:

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

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

And that compiles, links ans runs too. 然后编译,链接也运行。 So, I can say that the compiler (and of course according to the language) can instantiate the function and handle a function pointer to it. 因此,我可以说编译器(当然也根据语言)可以实例化函数并处理指向该函数的函数指针。

So, after that I tried to modify my original code, which is a derived class of HAshSet intended for managing pairs hashed by first field. 因此,在那之后,我尝试修改我的原始代码,这是HAshSet的派生类,用于管理由第一个字段散列的对。

I declare some as: 我声明为:

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>)
  {

  }

..
};

But the compilation (with std=c++11) fails with the error 但是编译(使用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; 

However, if I substitute the call to base constructor by 但是,如果我用以下方式代替对基本构造函数的调用

: HashSet<Key, Data>(wrapper<Key, Data, dft_hash_fct<Key>)

That compiles fine. 这样编译就可以了。 Thus, I believe that the problem is with the parameter type declaration (but I do not know what is). 因此,我认为问题在于参数类型声明(但我不知道是什么)。

The standard idiom to pass functions is to pass them as function objects, eg 传递函数的标准习惯用法是将它们作为函数对象传递,例如

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

Then call the wrapper using: 然后使用以下命令调用包装器:

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;
}

In your code, on the other hand: 另一方面,在您的代码中:

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

typename fct introduces an alias for a type. typename fct引入类型的别名。 Inside this function, fct names a type; 在此函数内, fct命名一个类型; therefore fct(p.first) creates an object of type fct , and this object needs to be converted to a size_t in order to return it from wrapper . 因此, fct(p.first)创建一个类型为fct的对象,并且需要将该对象转换为size_t才能从wrapper返回它。 You can use this as well, but the type you had to use would have to look like this: 您也可以使用它,但是必须使用的类型必须如下所示:

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

Which is probably not what you intended. 这可能不是您想要的。

The template declaration in 中的模板声明

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

declares template parameter fct as a type, but you are trying to pass a function pointer to it. 将模板参数fct声明为类型,但是您试图将函数指针传递给它。 You can make fct function pointer template parameter like this: 您可以使fct函数指针模板参数如下所示:

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

However, the more idiomatic way is (as DyP says) to pass a function object so that the function works with function pointers as well as objects overloading operator() : 但是,更惯用的方式是(如DyP所说)传递函数对象,以便函数与函数指针以及对象重载operator()

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

Then when calling it you pass the function as a parameter 然后在调用它时将函数作为参数传递

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

The code you wrote makes no sense within the context of your intent. 在您意图的上下文中,您编写的代码毫无意义。 Your fct template parameter is a type . 您的fct模板参数是type That means that 那意味着

return fct(p.first);

is a function-style cast , not an application of () operator (ie it is not a function call). 函数样式的强制转换 ,不是()运算符的应用程序(即,它不是函数调用)。 In your code you are attempting to cast p.first to type fct and then attempting to return the result of that cast as size_t . 在您的代码中,您尝试将p.first转换为fct类型,然后尝试p.first转换的结果作为size_t Was that your intent? 那是你的意图吗? I doubt that it was. 我怀疑是这样。 On top of that you are trying to pass a function pointer value dft_hash_fct<int> as a template argument for fct , ie you are passing a value where a type is expected. 最重要的是,您尝试传递函数指针 dft_hash_fct<int>作为fct的模板参数,即,您传递的是期望的类型 How did you expect it to work? 您希望它如何运作?

The description you provided seems to imply that you actually wanted to call a functor with type fct from inside wrapper instead of performing a cast. 您提供的描述似乎暗示您实际上是想从wrapper内部调用类型为fct函数,而不是执行强制转换。 In order to do that you have to obtain the functor itself somehow. 为此,您必须以某种方式获得函子本身。 Remember again that fct is not a functor, its is just the type of the functor. 再次记住, fct不是函子,它只是函子的类型

The typical approach would be to pass the functor from the outside, as function parameter 典型的方法是从外部传递函子作为函数参数

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

Now you can use your wrapper template with class-based functors, as well as with ordinary functions 现在,您可以将wrapper模板与基于类的函子以及普通函数一起使用

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

Note that dft_hash_fct<int> has to be supplied as function argument, not as template argument. 请注意, dft_hash_fct<int>dft_hash_fct<int>作为函数参数而不是模板参数提供。 There's no need to explicitly specify template arguments, since they will be deduced by the compiler. 无需显式指定模板参数,因为它们将由编译器推导。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM