(这个答案与@UncleBens 相同,但更通用一点,因为它可以完美转发任何参数。)
这在像 haskell 这样的语言中非常有用,例如,read
将字符串作为输入并根据所需的返回类型对其进行解析。
(这是ideone 上的示例代码。)
首先,从foo
我们希望推断其返回类型的函数开始:
template<typename Ret>
Ret foo(const char *,int);
template<>
std::string foo<std::string>(const char *s,int) { return s; }
template<>
int foo<int >(const char *,int i) { return i; }
当要求输入字符串时,它将返回其第一个参数中的字符串。当要求输入 int 时,它将返回第二个参数。
我们可以定义一个auto_foo
可以使用的函数,如下所示:
int main() {
std::string s = auto_foo("hi",5); std::cout << s << std::endl;
int i = auto_foo("hi",5); std::cout << i << std::endl;
}
为了完成这项工作,我们需要一个对象来临时存储函数参数,并在被要求转换为所需的返回类型时运行该函数:
#include<tuple>
template<size_t num_args, typename ...T>
class Foo;
template<typename ...T>
class Foo<2,T...> : public std::tuple<T&&...>
{
public:
Foo(T&&... args) :
std::tuple<T&&...>(std::forward<T>(args)...)
{}
template< typename Return >
operator Return() { return foo<Return>(std::get<0>(*this), std::get<1>(*this)); }
};
template<typename ...T>
class Foo<3,T...> : std::tuple<T&&...>
{
public:
Foo(T&&... args) :
std::tuple<T&&...>(std::forward<T>(args)...)
{}
template< typename Return >
operator Return() { return foo<Return>(std::get<0>(*this), std::get<1>(*this), std::get<2>(*this)); }
};
template<typename ...T>
auto
auto_foo(T&&... args)
// -> Foo<T&&...> // old, incorrect, code
-> Foo< sizeof...(T), T&&...> // to count the arguments
{
return {std::forward<T>(args)...};
}
此外,以上适用于两个参数或三个参数的函数,不难看出如何扩展它。
这要写很多代码!对于您将应用它的每个函数,您可以编写一个宏来为您执行此操作。文件顶部是这样的:
REGISTER_FUNCTION_FOR_DEDUCED_RETURN_TYPE(foo); // declares
// necessary structure and auto_???
然后你可以auto_foo
在你的程序中使用。