Специализация функции
От: DTF  
Дата: 20.11.17 01:34
Оценка:
Привет, коллективный разум.

Что-то ночь уже, и я не догоняю, почему вот такой код не компилируется:
template<typename T>
T foo() {
    T t;
    return t;
}

template<>
int foo<char>() {
    int i;
    return i;
}


(т.е. я хочу в определенных случаях возвращать другой тип, не тот, который обычно)

Что я делаю не так и как правильно делать?
Re: Специализация функции
От: Анатолий Широков СССР  
Дата: 20.11.17 07:15
Оценка: +1 -1
Здравствуйте, DTF, Вы писали:

DTF>Что я делаю не так и как правильно делать?


Я тебя сильно расстрою, если скажу, что частичной специализации шаблона функции в С++ нет? Помимо этого, тип результата функции не участвует в разрешении перегрузки. Поэтому следующий код просто не скомпилируется:

int foo() {
 return 10;
}
char foo() {
 return '1';
}


Все что можно посоветовать в этой ситуации, использовать специализацию класса:

template<typename T>
struct FooWrapper {
   static T foo() {
      ...
      return T{};
   }
};

template<>
struct FooWrapper<char> {
   static int foo() {
      ...
      return int(0);
   }
};


либо использовать полиси на тип возвращаемого результата, но с обобщенной реализацией foo:


template<typename T>
struct foo_return_policy {
    typedef T type;
};

template<typename T>
typename foo_return_policy<T>::type foo() {
 typename foo_return_policy<T>::type tmp;
 return tmp;
}

template<>
struct foo_return_policy<char> {
    typedef int type;
};

...
foo<char>();
foo<int>();
Отредактировано 20.11.2017 7:38 Анатолий Широков . Предыдущая версия .
Re: Специализация функции
От: F3V  
Дата: 20.11.17 07:30
Оценка: +3
Здравствуйте, DTF, Вы писали:

DTF>Что-то ночь уже, и я не догоняю, почему вот такой код не компилируется:

DTF>
DTF>template<typename T>
DTF>T foo() {
DTF>    T t;
DTF>    return t;
DTF>}

DTF>template<>
DTF>int foo<char>() {
DTF>    int i;
DTF>    return i;
DTF>}
DTF>


Компилятор пытается сопоставить специализацию с шаблоном и понимает, что подходящего ей шаблона нет.
В специализации указано foo<char>, т.е. предполагается что тип T == char.
Но в той же специализации на месте типа результата ожидается шаблоном тип T==char, а указан тип int.
Поэтому компилятор специализацию не принимает.

DTF>(т.е. я хочу в определенных случаях возвращать другой тип, не тот, который обычно)

DTF>Что я делаю не так и как правильно делать?

  template<typename T, typename T2 = T> T2 foo();
#include <iostream>

template<typename T, typename T2 = T>
T2 foo() {
    std::cout << " foo<T,T2>();" << std::endl;
    T t = 0;
    return t;
}

template<>
int foo<char>() {
    std::cout << " foo<char,int>();" << std::endl;
    int i = 0;
    return i;
}

int main()
{
    auto fC = foo<char>();
    auto fCI = foo<char, int>();
    return 0;
}
/*Output:
foo<T,T2>();
foo<char,int>();
*/
Re[2]: Специализация функции
От: uzhas Ниоткуда  
Дата: 20.11.17 10:32
Оценка: 73 (2) +1
Здравствуйте, Анатолий Широков, Вы писали:

АШ>Я тебя сильно расстрою, если скажу, что частичной специализации шаблона функции в С++ нет?

это конечно занимательный факт, однако не имеет отношение к вопросу, т.к. у ТС нет и не подразумеваются частичные специализации (у него есть полные специализации, которые работают и для шаблонных функций)

АШ>Помимо этого, тип результата функции не участвует в разрешении перегрузки.

и это не имеет отношение к вопросу, т.к. ТС спрашивает как сделать специализацию функции, а не как это вызвать
а делается она вот так: https://ideone.com/wAoErC (тут и вызовы показаны)
можно и так: https://ideone.com/73DVmt
проблема у ТС в том, что он попытался изменить сигнатуру функции так, что это встало в противоречие с объявленной шаблонной функцией : тип шаблона должен совпадать с типом результата функции (ошибка компиляции явно об этом говорит)

по поводу вариантов решения задачи "хочу в определенных случаях возвращать другой тип, не тот, который обычно", то тут их море, включая вариант отказа от специализаций функций как таковых, как и советуют умные люди типа Мейерса. способ можно подобрать оптимальнее, если понять исходную задачу лучше (нужны примеры что за функции, что возвращают и почему разного типа)
Re[3]: Специализация функции
От: Анатолий Широков СССР  
Дата: 20.11.17 11:03
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Анатолий Широков, Вы писали:


АШ>>Я тебя сильно расстрою, если скажу, что частичной специализации шаблона функции в С++ нет?

U>это конечно занимательный факт, однако не имеет отношение к вопросу, т.к. у ТС нет и не подразумеваются частичные специализации (у него есть полные специализации, которые работают и для шаблонных функций)

АШ>>Помимо этого, тип результата функции не участвует в разрешении перегрузки.

U>и это не имеет отношение к вопросу, т.к. ТС спрашивает как сделать специализацию функции, а не как это вызвать
U>а делается она вот так: https://ideone.com/wAoErC (тут и вызовы показаны)
U>можно и так: https://ideone.com/73DVmt
U>проблема у ТС в том, что он попытался изменить сигнатуру функции так, что это встало в противоречие с объявленной шаблонной функцией : тип шаблона должен совпадать с типом результата функции (ошибка компиляции явно об этом говорит)

Да, ты прав.
Re: Специализация функции
От: rg45 СССР  
Дата: 21.11.17 21:05
Оценка:
Здравствуйте, DTF, Вы писали:

DTF>(т.е. я хочу в определенных случаях возвращать другой тип, не тот, который обычно)

DTF>Что я делаю не так и как правильно делать?

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

// C++03 compatible
template<typename T>
struct FooImpl
{
  typedef T ReturnType;
  ReturnType operator()() const {
    ReturnType t;
    return t;
  }
};

template<>
struct FooImpl<char>
{
  typedef int ReturnType;
  ReturnType operator()() const {
    ReturnType t;
    return t;
  }
};

template<typename T>
typename FooImpl<T>::ReturnType foo() {
    return FooImpl<T>()();
}
--
Не можешь достичь желаемого — пожелай достигнутого.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.