1

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

我的许多尝试之一是

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

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

我正在使用declval result_of auto decltype没有任何运气。

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

如果有人想知道我为什么要尝试对此进行创意,那是我正在尝试以可行/简洁的方式在 C++11 中实现一些 Currying。

4

3 回答 3

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

它并不能完全解决处理重载集的问题,但它相当接近。我尝试了这个想法,本质上也是为了在改进的标准库算法系统的上下文中进行柯里化,我倾向于算法实际上是函数对象而不是函数(这也是出于各种其他原因而需要的;例如,您无需担心何时要使用另一个算法自定义算法)。

于 2013-12-06T00:23:48.523 回答
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.");
}

是的,它很冗长,因为您正在尝试显式提取隐式临时重载为您所做的事情。

于 2013-12-06T00:26:06.947 回答
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;
};
于 2013-12-05T23:51:37.110 回答