“Overload” function template based on function object operator() signature

≯℡__Kan透↙ 提交于 2019-12-08 07:14:46

问题


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

And doing so is transparent:

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?

Specifically, I want this to compile:

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

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

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

error: no matching function for call to 'map_vec'

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

Update: C++98 version of this question

“Overload” function template based on function object operator() signature in C++98


回答1:


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

Demo



来源:https://stackoverflow.com/questions/27321959/overload-function-template-based-on-function-object-operator-signature

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!