2014-09-17 4 views
10

У меня есть следующая проблема: я просто не вижу правильного решения (и, возможно, нет): у меня есть шаблонный метод, в котором тип возврата зависит от ввода тип, и благодаря C++ 11 decltype тип возврата может быть получен легко, , но Я также хотел бы разрешить пользователю задавать тип возврата явно при желании.C++ function template: Производный и явный тип возвращаемого значения

Более формально у меня есть шаблонная функция f, что я хотел бы быть вызван как f(x), при этом ни входной, ни возвращаемый тип явно не определены. И я также хотел бы назвать его f<ret_t>x() с явно выраженным типом возвращаемого значения, но тип ввода все равно будет получен автоматически.

Теперь, удовлетворяя первое ограничение с C++ 11 легко (давайте предположим, что есть еще один шаблонный метод:

template<typename InT> 
auto f(const InT& in) -> decltype(/* code deriving the return type using in */); 

Но это не позволит подмена возвращаемого типа, для этого я бы добавить он в качестве второго параметра шаблона и переместить decltype вывод в определении шаблона и, вероятно, необходимо использовать std::declval<InT> или std::result_of:

template< 
    typename InT, 
    typename RetT = /* code deriving return type using InT and declval/result_of */> 
RetT f(const InT& in); 

Однако, этот способ мне всегда нужно явным образом d efine InT при звонке f. Таким образом, декларация f для того, чтобы иметь возможность оставить InT открытым, но указать RetT должно быть:

template< 
    typename RetT = /* code deriving return type using InT and declval/result_of */, 
    typename InT> 
RetT f(const InT& in); 

Но так как в момент, когда мне нужно указать значение по умолчанию для RetT, InT еще не доступен и, следовательно, не может использоваться.

Наилучшее обходное решение, с которым я мог придумать до сих пор, что не очень удовлетворительно и, похоже, не работает, поскольку вычет RetT не удается (видимо, из-за того, что вы не можете выводить типы из аргументов по умолчанию) является:

template<typename RetT, typename InT> 
RetT f(
    const InT& in, 
    const RetT& = std::declval</* code deriving return type using InT or in and declval/result_of */>()); 

есть ли более эффективные способы, чтобы иметь значение по умолчанию для RetT, который зависит от InT в то время как еще в состоянии явно указать RetT при желании? Важно отметить, что тип возвращаемого значения должен быть доступен в реализации функции, чтобы объект RetT был выделен напрямую и только один раз внутри тела метода.

+0

Последняя строка разбивается двумя способами: вы не можете УСО-использовать 'declval' и вы не можете вывести из аргумента по умолчанию. –

+0

@Niall: Да, 'result_of', вероятно, сработает. Но проблема в том, что порядок аргументов в этом случае. –

+0

@ T.C.: Теперь, когда вы упомянули об этом, да, вы не можете вывести из аргумента по умолчанию. Я расскажу об этом. –

ответ

10

Вы можете использовать std::conditional и тип dummy, чтобы проверить, имеет ли функция автоматический выведенный тип или выбранный пользователем тип.

Если пользователь явно выбирает тип возврата, тип возврата будет чем-то иным, чем тип dummy, и это будет тип возвращаемого значения функции. В противном случае просто используйте выведенный тип, как и раньше.

После одного из примеров использования:

#include <typeindex> 
#include <type_traits> 
#include <iostream> 

struct dummy 
{ 
}; 

template<typename RetType = dummy, typename T> 
auto f(const T& in) 
-> typename std::conditional<std::is_same<RetType, dummy>::value, T, RetType>::type 
{ 
    std::cout<<typeid(RetType).name()<<" "<<typeid(T).name()<<std::endl; 
    return in; 
} 

int main() 
{ 
    f(1); 
    f<float>(1); 
} 
+0

Возможно, даже не нужно использовать 'dummy' -' void', вероятно, достаточно. –

+0

@ T.C. Если пользователь выбирает void как возвращаемый тип, будет использоваться автоматически выводимый тип. Я не думаю, что это желательно – Felics

+0

Аргумент шаблона по умолчанию перед не-дефолтными ... Я этого не знал. Это здорово. – Niall

Смежные вопросы