“过载”基于函数对象operator()签名的函数模板 [英] "Overload" function template based on function object operator() signature

查看:259
本文介绍了“过载”基于函数对象operator()签名的函数模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一个函数模板的示例,它将一个函数引用作为它的第一个参数。它基于第一个参数的函数签名重载。

Consider this example of a function template that takes a function reference as its first argument. It is overloaded based on the function signature of that first argument. The body of each overload feeds the 1st argument function appropriately for it's signature.

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;
}

由于重载,对这些函数的引用可以作为第一个参数:

Because of the overload, a reference to either of these functions can be passed as the 1st 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);

上面使用的重载策略不能用于函数对象,因为对象本身没有签名本身。假设感兴趣的函数对象如下。

The overloading strategy used above won't work for function objects since the object itself doesn't have a signature per se. Suppose the function objects of interest are the following.

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_;
};

如何更改函数模板以接受函数对象和函数, ?

How can I change the function templates to accept both the function objects and the functions and overload based on how the call should be made?

具体来说,我要编译:

const AddNum add2(2);
const auto c = map_vec(add2, v);

const AddNumMulSize add2mulsz(2);
const auto d = map_vec(add2mulsz, v);

clang提供的错误消息非常清楚,符合您预期的结果。

The error message that clang gives is quite clear and matches what you would expect.


错误:没有匹配的函数调用'map_vec'

error: no matching function for call to 'map_vec'

候选函数[with T = int ]不可行:从
'const AddNum'到第一个参数的已知转换:'typename MapTtoT :: type&'(aka'int(&)(const int)')

candidate function [with T = int] not viable: no known conversion from 'const AddNum' to 'typename MapTtoT::type &' (aka 'int (&)(const int)') for 1st argument

更新:此问题的C ++ 98版本

Update: C++98 version of this question

基于函数对象的Overload函数模板operator()签名在C ++ 98

推荐答案

更改您的签名通常采用类型 F ,则可以使用expression-SFINAE来限制基于 F 可以调用的重载:

Change your signature to generically take a function object of type F, then you can use expression-SFINAE to restrict overloads based on what F can be called with:

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>{});

演示

这篇关于“过载”基于函数对象operator()签名的函数模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆