考虑一个函数模板的示例,该函数模板将函数引用作为其第一个参数。它根据第一个参数的函数签名重载。每个重载的主体为其签名适当地提供第一个参数函数。
template<typename T>
struct MapTtoT { typedef T (type)(const T); };
template<typename T>
std::vector<T> map_vec(
const typename MapTtoT<T>::type& fnc,
const std::vector<T>& source)
{
std::vector<T> dest;
dest.reserve(source.size());
for (const auto i : source)
{
dest.emplace_back(fnc(i));
}
return dest;
}
template<typename T>
struct MapTandVectoT { typedef T (type)(const T, const std::vector<T>&); };
template<typename T>
std::vector<T> map_vec(
const typename MapTandVectoT<T>::type& fnc,
const std::vector<T>& source)
{
std::vector<T> dest;
dest.reserve(source.size());
for (const auto i : source)
{
dest.emplace_back(fnc(i, source));
}
return dest;
}
由于过载,对这两个函数的引用可以作为第一个arg传递:
int foo(const int x);
int bar(const int x, const std::vector<int>& v);
这样做是透明的:
const auto a = map_vec(foo, v);
const auto b = map_vec(bar, v);
上面使用的重载策略不适用于函数对象,因为对象本身并没有签名。假设感兴趣的函数对象如下。
class AddNum
{
public:
AddNum(const int num) : num_(num) {}
int operator()(const int x) const
{
return x + num_;
}
private:
const int num_;
};
class AddNumMulSize
{
public:
AddNumMulSize(const int num) : num_(num) {}
int operator()(const int x, const std::vector<int>& v) const
{
return (x + num_) * v.size();
}
private:
const int num_;
};
如何根据调用方式更改函数模板以接受函数对象和函数以及重载?
具体来说,我想要编译:
const AddNum add2(2);
const auto c = map_vec(add2, v);
const AddNumMulSize add2mulsz(2);
const auto d = map_vec(add2mulsz, v);
clang给出的错误消息非常清楚,并且符合您的预期。
错误:没有用于调用&#39; map_vec&#39;
的匹配功能候选函数[使用T = int]不可行:没有已知的转换 &#39; const AddNum&#39;到&#39; typename MapTtoT :: type&amp;&#39; (又名&#39; int(&amp;)(const int)&#39;)第一个参数
更新:此问题的C ++ 98版
“Overload” function template based on function object operator() signature in C++98
答案 0 :(得分:6)
更改您的签名以通常采用类型为F
的函数对象,然后您可以使用表达式-SFINAE来根据可以调用的F
来限制重载:
template<typename F, typename T>
auto map_vec(F&& fnc, const std::vector<T>& source)
-> decltype(void(fnc(std::declval<T>())), std::vector<T>{});
template<typename F, typename T>
auto map_vec(F&& fnc, const std::vector<T>& source)
-> decltype(void(fnc(std::declval<T>(), source)), std::vector<T>{});