减去重载函数的类型 - currying

时间:2013-12-05 23:39:56

标签: c++ templates c++11 currying combinatory-logic

给定一个可调用对象(函数)a和一个参数b(或一系列参数),我想推断f返回的类型,考虑到{ {1}}重载了多个签名。

我的许多尝试之一是

f

和2个模板选项被注释掉并包含在前面的代码中。

我正在使用#include <iostream> #include <cstdint> #include <string> #include <functional> #include <utility> #include <typeinfo> int foo(uint32_t a) { return ((a + 0) * 2); } bool foo(std::string a) { return (a.empty()); } /*template <typename A, typename B> auto bar(A a, B b) -> decltype(a(b)) { return (a(b)); }*/ /*template <typename A, typename B> decltype(std::declval<a(b)>()) bar(A a, B b) { return (a(b)); }*/ template <typename A, typename B> void bar(std::function<A(B)> a, B b) { std::cout << a(b) << "\n"; } int main() { // the following 2 lines are trivial and they are working as expected std::cout << foo(33) << "\n"; std::cout << typeid(decltype(foo(std::string("nothing")))).name() << "\n"; std::cout << bar(foo, 33) << "\n"; //std::cout << bar(foo, std::string("Heinz")) << "\n"; return (0); } 而没有任何运气。

重载解析过程如何在编译时工作?

如果有人想知道我为什么要尝试创造这个,那就是我正在尝试以可行/整洁的方式在C ++ 11中实现一些Currying。

3 个答案:

答案 0 :(得分:4)

问题是你不能轻易地从重载集创建一个函数对象:当你声明foo&foo时(在大多数情况下,函数会衰减成函数指针,我认为)你没有得到一个对象,但你得到一个重载集。您可以通过调用它或提供其签名来告诉编译器您想要哪个重载。据我所知,你也不想要。

我唯一知道的方法是将你的函数变成一个实际的函数对象,这会让问题消失:

struct foo_object
{
    template <typename... Args>
    auto operator()(Args&&... args) -> decltype(foo(std::forward<Args>(args)...)) {
        return foo(std::forward<Args>(args)...);
    }
};

使用每个名称不幸需要的包装器,您可以简单地推断出返回类型,例如:

template <typename Func, typename... Args>
auto bar(Func func, Args&&... args) -> decltype(func(std::forward<Args>(args)...)) {
    // do something interesting
    return func(std::forward<Args>(args)...);
}

int main() {
    bar(foo_object(), 17);
    bar(foo_object(), "hello");
}

它并没有完全解决处理过载集的问题,但它相当接近。我试验了这个想法,主要是为了在标准库算法的改进系统的环境中进行干扰,我倾向于算法实际上是函数对象而不是函数(这也是出于各种其他原因所希望的;例如,当你想用另一个算法自定义算法时,你不需要做什么。)

答案 1 :(得分:3)

如果foo超载,则需要使用以下内容:

#include <type_traits>

int foo(int);
float foo(float);

int main() {
    static_assert(std::is_same<decltype(foo(std::declval<int>())), int>::value, "Nope.");
    static_assert(std::is_same<decltype(foo(std::declval<float>())), float>::value, "Nope2.");
}

如果不是,那就足够了:

#include <type_traits>
bool bar(int);

int main() {
    static_assert(std::is_same<std::result_of<decltype(bar)&(int)>::type, bool>::value, "Nope3.");
}

是的,它很冗长,因为你试图明确地提取隐式ad-hoc重载为你做的事情。

答案 2 :(得分:2)

这实际上已经为您std::result_of实施了。这是一个可能的实现

template<class>
struct result_of;

// C++11 implementation, does not satisfy C++14 requirements
template<class F, class... ArgTypes>
struct result_of<F(ArgTypes...)>
{
    typedef decltype(
                     std::declval<F>()(std::declval<ArgTypes>()...)
                    ) type;
};