简体   繁体   中英

C++11 Type Deduction With std::function

Even after reading many online resources and other questions, including template argument type deduction from std::function return type with lambda and Argument type auto deduction and anonymous lambda functions , I am struggling with clearly expressing the following in c++. I would like to avoid duplicate template arguments, which seem unnecessary.

For example, container 'H' of generic type 'A' has a generic method 'M' for generic type 'B'. This expresses my intent for 'H' and method 'M':

template<typename A>
struct H
{
    explicit H(A x) : x(x) { }
    A x;

    template<typename B>
    H<B> M(std::function<H<B>(A)> g) { return g(x); }
};

My issue is calling 'M' requires duplicate template arguments for the function call and return container. For type 'float', this isn't too bad, but with other symbols this gets unmanageable very quickly.

// This works but requires the duplicate 'float'
H<int>(1).M<float>([](int x) { return H<float>(x + 3.14); });

// These would be preferred, but neither works
H<int>(1).M<float>([](int x) { return H(x + 3.14); });
H<int>(1).M([](int x) { return H<float>(x + 3.14); });

From this question , I tried a new definition of 'H' with a generic functor type 'F' instead of a generic result type:

template<typename A>
struct H2
{
    enum { IS_H2 = true };

    explicit H2(A x) : x(x) { }
    A x;

    template<typename F,
        class = typename std::enable_if<std::result_of<F(A)>::type::IS_H2>::type>
    auto M(F g) -> decltype(g(x)) { return g(x); }
};

which allows the desired syntax:

// This now is valid
H2<int>(1).M([](int x) { return H2<float>(x + 3.14); });

// And, as expected, this is not
H2<int>(1).M([](int x) { return x + 3.14; });

But I find 'H2' almost offensive, there has to be a better way.

How can either the generic return type of a functor be restricted more cleanly or std::function be made to work with type inference? Or am I attacking the problem from the wrong angle entirely?

That is how function template works, and there are no ways around.

Automatic template parameter deduction is done if you have a parameter in the function parameter, which is here not the case. For example, the compiler can deduce type in this function :

template<typename B>
H<B> M(std::function<H<B>(A)> g, const B&) { return g(x); }

but then you would have to pass some dummy value, which is (I think) not what you want.


Here is the example, which can not convert lambda into std::function, because template parameter deduction fails :

#include <functional>

template<typename A>
struct H
{
    explicit H(A x) : x(x) { }
    A x;

    template<typename B>
    H<B> M(std::function<H<B>(A)> g, const B&) { return g(x); }
};

int main()
{
    H<int> h(1);

    std::function<H<float>(int)> g( [](int x){ return H<float>(x + 3.14); } );
    const auto v = h.M( g, 5.5f );

    (void)v;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM