(Этот ответ такой же, как и у @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
в своей программе.
08.11.2013