Как я могу использовать std :: enable_if с само-выводимым типом возврата?

C ++ 14 будет иметь функции, чей тип возврата может быть выведен на основе возвращаемого значения.

auto function(){
return "hello world";
}

Могу ли я применить это поведение к функциям, которые используют enable_if для СФИНА по типу возвращаемого значения?

Например, давайте рассмотрим следующие две функции:

#include <type_traits>
#include <iostream>

//This function is chosen when an integral type is passed in
template<class T >
auto function(T t) -> typename std::enable_if<std::is_integral<T>::value>::type {
std::cout << "integral" << std::endl;
return;
}

//This function is chosen when a floating point type is passed in
template<class T >
auto function(T t) -> typename std::enable_if<std::is_floating_point<T>::value>::type{
std::cout << "floating" << std::endl;
return;
}

int main(){

function(1);    //prints "integral"function(3.14); //prints "floating"
}

Как видите, правильная функция выбирается с помощью SFINAE по типу возвращаемого значения.
Тем не менее, это обе пустые функции. Второй параметр enable_if по умолчанию установлено void, Это было бы то же самое:

//This function is chosen when an integral type is passed in
template<class T >
auto function(T t) -> typename std::enable_if<std::is_integral<T>::value, void>::type {
std::cout << "integral" << std::endl;
return;
}

//This function is chosen when a floating point type is passed in
template<class T >
auto function(T t) -> typename std::enable_if<std::is_floating_point<T>::value, void>::type{
std::cout << "floating" << std::endl;
return;
}

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

GCC 4.8.2 (используя --std=c++1y)

12

Решение

std::enable_if необязательно указывать возвращаемый тип, так как в C ++ 11 он может быть частью параметров шаблона.

Таким образом, ваши эквивалентные функции могут быть (или, ну, что-то в этом роде):

enum class enabler_t {};

template<typename T>
using EnableIf = typename std::enable_if<T::value, enabler_t>::type;

//This function is chosen when an integral type is passed in
template<class T, EnableIf<std::is_integral<T>>...>
auto function(T t) {
std::cout << "integral" << std::endl;
return;
}

//This function is chosen when a floating point type is passed in
template<class T, EnableIf<std::is_floating_point<T>>...>
auto function(T t) {
std::cout << "floating" << std::endl;
return;
}

Это также может быть параметр в функции:

//This function is chosen when an integral type is passed in
template<class T>
auto function(T t, EnableIf<std::is_integral<T>>* = nullptr) {
std::cout << "integral" << std::endl;
return;
}

//This function is chosen when a floating point type is passed in
template<class T>
auto function(T t, EnableIf<std::is_floating_point<T>>* = nullptr) {
std::cout << "floating" << std::endl;
return;
}

Это сохранит автоматическое удержание типа и SFINAE.

11

Другие решения

std::enable_if может быть типом возврата, параметром функции или параметром шаблона. Вы получите ошибку переопределения функции, если вы используете тип возвращаемого значения или параметр шаблона, поэтому вам нужно использовать std::enable_if в качестве параметра функции:

#include <type_traits>
#include <iostream>

template<class T, typename = typename std::enable_if<std::is_integral<T>::value, void>::type>
auto function(T t, typename std::enable_if<std::is_integral<T>::value, void>::type* dummy = nullptr) {
std::cout << "integral" << std::endl;
return 0;
}

//This function is chosen when a floating point type is passed in
template<class T, typename = typename std::enable_if<std::is_floating_point<T>::value, void>::type>
auto function(T t, typename std::enable_if<std::is_floating_point<T>::value, void>::type* dummy = nullptr) {
std::cout << "floating" << std::endl;
return 0.0f;
}

int main()
{
auto ret = function(0); // integral
auto ret2 = function(0.0f); // floating
std::cout << std::boolalpha << std::is_integral<decltype(ret)>::value << std::endl; // true
std::cout << std::is_floating_point<decltype(ret2)>::value << std::endl; // true
}
6

В строке ответа @ user1508519 мы можем удалить параметр enable_if из метода и сохранить его только в качестве параметра шаблона.
Мы полагаемся на то, что enable_if<false> не определяет type, так enable_if<false>::type, который не существует, является хорошим инструментом для SFINAE — в сигнатуре метода, которая включает параметры шаблона.

Нет необходимости использовать этот параметр шаблона в самом методе!

Таким образом:

template<class T,
typename std::enable_if<std::is_integral<T>::value>::type* dummy = nullptr>
auto function(T t) {
std::cout << "integral" << std::endl;
return 0;
}

// This function is chosen when a floating point type is passed in
template<class T,
typename std::enable_if<std::is_floating_point<T>::value>::type* dummy = nullptr>
auto function(T t) {
std::cout << "floating" << std::endl;
return 0.0f;
}

int main() {
auto ret = function(0); // integral
auto ret2 = function(0.0f); // floating
cout << std::boolalpha;
cout << std::is_integral<decltype(ret)>::value << endl; // true
cout << std::is_floating_point<decltype(ret2)>::value << endl; // true
}

Выход

integral
floating
true
true
2

Как уже упоминалось в другом месте std::enable_if может использоваться для формирования любого типа возврата; параметр функции; или параметр шаблона.

Однако последние два метода имеют недостаток в том, что они изменяют сигнатуру соответствующей функции или объекта. С помощью std::enable_if с другой стороны, при возвращаемом типе количество параметров функции и шаблона остается неизменным.

С автоматическим выводом лямбда-типов возврата в C ++ 11 (вероятно, распространяемых на обычные функции в C ++ 14) было бы идеально, если бы существовал метод, позволяющий выводить оба типа возврата; а также использование std::enable_if на тип возврата. Чтобы съесть свой торт и съесть его — почти. Увы, кажется, что в настоящее время это невозможно.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector