给定一个可调用对象(函数)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。
答案 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;
};