(g ++ 4.7.1)用等效的类typedef替换显式类型名称无法编译

时间:2012-09-03 17:15:38

标签: c++ templates c++11 g++

我试图创建一个接受迭代和函数的模板化函数,这样传递的函数将被隐式地转换为适当类型的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 ++中的已知错误?

2 个答案:

答案 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类型以进行类型扣除。