C++ 函数作为模板参数
c++ functions as template arguments
我遇到了一些问题,可以通过以下代码段恢复:
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在构建时接收哈希函数。
感谢您的评论(大卫、安德烈和卡扎克)
编辑:
好吧,我明白了,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;
并且编译,链接和运行。因此,我可以说编译器(当然根据语言)可以实例化函数并处理指向它的函数指针。
因此,在那之后,我尝试修改我的原始代码,这是 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>)
编译得很好。因此,我认为问题出在参数类型声明上(但我不知道是什么)。
传递函数的标准习惯用法是将它们作为函数对象传递,例如
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; }
};
这可能不是您的意图。
中的模板声明
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>);
您编写的代码在您的意图上下文中毫无意义。fct
模板参数是一种类型。这意味着
return fct(p.first);
是函数样式的强制转换,而不是()
运算符的应用程序(即它不是函数调用)。在代码中,您尝试将p.first
转换为类型 fct
,然后尝试将该强制转换的结果返回为 size_t
。这是你的意图吗?我怀疑是不是。最重要的是,您尝试传递函数指针值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>
必须作为函数参数提供,而不是作为模板参数提供。无需显式指定模板参数,因为它们将由编译器推导。
- 将可变参数函数的参数封装在类实例中
- QML 使用带有参数C++函数
- 使用可变参数函数作为模板参数
- 如何在C++中伪造虚拟可变参数函数模板?
- 为什么可变参数函数不适用于模板
- C++ std::functional 中的可变参数函数模板
- 可变参数函数指针的定义对于VxWorks spyLib来说不清楚
- 使用可变参数函数覆盖具有不同函数签名的虚函数
- 考虑引用和常量的可变参数函数包装器
- 使用可变参数函数将整数和/或整数数组放入单个 int 数组中
- 在可变参数函数中转发特定范围的参数
- 通过引用传递参数;函数返回类型是否必须为 VOID?
- 使用带有一个参数函数的递归找到数字的平方
- 可变参数函数模板不能很好地使用 std::function 作为参数
- 多个可变参数函数的单个模板参数包?
- 参数数据类型未知的可变参数函数
- 可变参数函数参数包扩展
- 使用模板可变参数函数将多个参数传递给另一个函数
- 对可变参数函数的递归调用的链接器错误
- 通过像printf这样的可变参数函数传递一个带有常量字符*转换函数的类