6

我正在尝试创建一个接受可迭代和函数的模板化函数,这样传递的函数将被隐式转换为std::function适当类型的 a(从而允许它与完整函数和 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++ 而不是 clang。我做错了什么,或者这是g ++中的一个已知错误?

4

2 回答 2

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显式实例化(as 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));
}
于 2012-09-03T17:35:01.370 回答
2

您需要指针函数的第二个重载 - 然后它将编译。隐式强制转换std::function不起作用:

void bar(const T & base, bool(*f)(typename T::value_type)){
    std::cout << "ptr func\n";
}

解决 ecatmur 描述的问题(几个 T,函数signutre 中的类型不匹配):您可以将其他 T 包装在identitystruct 中,其定义如下:

template<class T> struct identity{ typedef T type; };

然后编译器将忽略这些 T 进行类型推导。

于 2012-09-03T18:33:58.243 回答