我试图创建一个接受迭代和函数的模板化函数,这样传递的函数将被隐式地转换为适当类型的std::function
(从而允许它与完整的功能和lambdas)。
以下是代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <typeinfo>
template<typename T>
void bar(const T & base, std::function<bool(int)> f) // works
//void bar(const T & base, std::function<bool(typename T::iterator::value_type)> f) // fails to compile
{
std::cout << ((typeid(std::function<bool(int)>) == typeid(std::function<bool(typename T::iterator::value_type)>))?"identical":"distinct") << std::endl;
}
bool filter(int x) { return x%2==0; }
int main() { bar(std::vector<int> {0, 1}, filter); }
使用g++-4.7 -std=c++11 -o itest itest.cpp
进行编译,这会生成identical
。
如果取消注释第10行和注释第9行并按上述方式进行编译,则编译将失败并显示
g++-4.7 -std=c++11 -Wall -Werror -o itest itest.cpp
itest.cpp: In function 'int main()':
itest.cpp:16:53: error: no matching function for call to 'bar(std::vector<int>, bool (&)(int))'
itest.cpp:16:53: note: candidate is:
itest.cpp:9:10: note: template<class T> void bar(const T&, std::function<bool(typename T::iterator::value_type)>)
itest.cpp:9:10: note: template argument deduction/substitution failed:
itest.cpp:16:53: note: mismatched types 'std::function<bool(typename T::iterator::value_type)>' and 'bool (*)(int)'
我应该注意到未修改的版本使用Xcode(设置了适当的选项)成功,但是如果可能的话,我更愿意坚持使用g ++ over clang。我做错了什么,或者这是g ++中的已知错误?
答案 0 :(得分:5)
很抱歉,但错误在您的代码中。它相当于:
template<typename T> struct S { template<typename U> S(const U &); };
template<typename T> void bar(T, S<T>);
int main() { bar(5, 6); }
问题在于,在模板参数推导/替换中,如果模板参数出现(直接或在构造依赖类型中)在多个参数中,则两个参数必须完全匹配;不考虑用户定义的转换,即使从一个参数中明显看出类型必须是什么。
此处的用户定义转换是std::function<...>
的隐式构造函数。
可能的解决方法是显式实例化bar
(如bar<int>
),或派遣到辅助函数:
template<typename T>
void bar_impl(const T & base, std::function<bool(typename T::iterator::value_type)> f)
{
std::cout << ((typeid(std::function<bool(int)>) == typeid(std::function<bool(typename T::iterator::value_type)>))?"identical":"distinct") << std::endl;
}
template<typename T, typename F>
void bar(const T & base, F &&f)
{
bar_impl<T>(base, std::forward<F>(f));
}
答案 1 :(得分:2)
你需要第二次重载指针函数 - 然后它将编译。对std::function
的隐式转换不会起作用:
void bar(const T & base, bool(*f)(typename T::value_type)){
std::cout << "ptr func\n";
}
解决ecatmur描述的问题(几个T,在函数signutre中没有匹配的类型):你可以在identity
结构中包装其他T,其定义如下:
template<class T> struct identity{ typedef T type; };
然后编译器将忽略这些T类型以进行类型扣除。