Чому шаблон функції не може бути частково спеціалізованим?


87

Я знаю, що специфікація мови забороняє часткову спеціалізацію шаблону функції.

Я хотів би знати обгрунтування, чому це забороняє? Вони не корисні?

template<typename T, typename U> void f() {}   //allowed!
template<> void f<int, char>()            {}   //allowed!
template<typename T> void f<char, T>()    {}   //not allowed!
template<typename T> void f<T, int>()     {}   //not allowed!

Для template<typename T, typename U> void f(T t, U u) {}також template<> void f(int t, char u) {}дозволено.
dashesy

10
Мені цікаво, що люди продовжують надавати обхідні шляхи, коли питання полягає не в тому, "як я можу досягти подібної мети", а "в чому полягає обгрунтування цієї поведінки" ... Я сам не знаю причину такого вибору, але я припускаю, що у комітету, мабуть, була причина заборонити часткову спеціалізацію шаблону функцій. Поки що "найближчим" поясненням є посилання, розміщене Георгієм, яке лише вказує на потенційні "ризики" часткової спеціалізації шаблону функцій, коли є перевантаження. Однак, я не думаю, що це є причиною заборонити цю функцію, тому я припускаю, що в цьому є ще
щось

Відповіді:


59

AFAIK, що змінено на C ++ 0x.

Я припускаю, що це був просто недогляд (враховуючи, що ви завжди можете отримати ефект часткової спеціалізації за допомогою більш детального коду, розмістивши функцію як staticчлена класу).

Ви можете переглянути відповідний DR (Звіт про дефекти), якщо він є.

РЕДАКТУВАТИ : перевіряючи це, я виявляю, що інші також вірили в це, але ніхто не може знайти такої підтримки в проекті стандарту. Цей потік SO, схоже, вказує на те, що часткова спеціалізація шаблонів функцій не підтримується в C ++ 0x .

EDIT 2 : лише приклад того, що я мав на увазі під "розміщенням функції як staticчлена класу":

#include <iostream>
using namespace std;

// template<typename T, typename U> void f() {}   //allowed!
// template<> void f<int, char>()            {}   //allowed!
// template<typename T> void f<char, T>()    {}   //not allowed!
// template<typename T> void f<T, int>()     {}   //not allowed!

void say( char const s[] ) { std::cout << s << std::endl; }

namespace detail {
    template< class T, class U >
    struct F {
        static void impl() { say( "1. primary template" ); }
    };

    template<>
    struct F<int, char> {
        static void impl() { say( "2. <int, char> explicit specialization" ); }
    };

    template< class T >
    struct F< char, T > {
        static void impl() { say( "3. <char, T> partial specialization" ); }
    };

    template< class T >
    struct F< T, int > {
        static void impl() { say( "4. <T, int> partial specialization" ); }
    };
}  // namespace detail

template< class T, class U >
void f() { detail::F<T, U>::impl(); }    

int main() {
    f<char const*, double>();       // 1
    f<int, char>();                 // 2
    f<char, double>();              // 3
    f<double, int>();               // 4
}

у вас є стандарт в n3225? Я зробив швидкий пошук, але не зміг його знайти: /
Matthieu M.

1
ах вибачте ... слова не вистачало. Я маю документ, але не зміг знайти конкретний параграф . Хоча, враховуючи вашу редакцію, я думаю, це просто тому, що її там немає :)
Matthieu M.

3
Це не змінено в C ++ 0x. Я також сумніваюся в його корисності. Ви завжди можете перевантажити шаблон і використати часткове впорядкування .
Йоганнес Шауб - літ

1
Пізнє оновлення: не змінилося навіть у C ++ 17 через вісім років і, схоже, також не входить у C ++ 20. Не бачу жодної причини, але ...
Аконкагуа,

Я вважаю, що це, безумовно, найповніша реалізація концепції
Віктор

18

Ну, ви дійсно не можете зробити часткову спеціалізацію функцій / методів, однак ви можете зробити перевантаження.

template <typename T, typename U>
T fun(U pObj){...}

// acts like partial specialization <T, int> AFAIK 
// (based on Modern C++ Design by Alexandrescu)
template <typename T>
T fun(int pObj){...} 

Це шлях, але я не знаю, чи задовольнить він вас.


1
Вау, мій розум був наповнений такими шаблонами, що я справді забув, наскільки простими можуть бути речі :)
Йоганнес

1
На жаль, це не той випадок, коли ви хочете передати варіативні аргументи після часткової спеціалізації функції .. :(
Gwangmu Lee

Я не впевнений, що малося на увазі під передачею варіативних шаблонів, тому я хотів би знати, чим це відрізняється від часткової спеціалізації. Не могли б ви надати більше деталей?
beginpluses

Що робити, якщо вам потрібні лише дві функції для всіх цілісних і плаваючих типів?
Дмитро Докшин

14

Загалом, не рекомендується спеціалізуватись на шаблонах функцій взагалі через проблеми з перевантаженням. Ось хороша стаття з журналу користувачів C / C ++: http://www.gotw.ca/publications/mill17.htm

І він містить чесну відповідь на ваше запитання:

З одного боку, ви не можете частково їх спеціалізувати - в основному лише тому, що мова говорить, що ви не можете.


3
Стаття не стосується часткової спеціалізації, крім того, що вона згадується один раз.
Euri Pinhollow,

11

Оскільки ви можете частково спеціалізуватись на заняттях, ви можете використовувати функтор:

#include <iostream>

template < typename dtype , int k > struct fun
{
 int operator()()
 {
  return k ;
 }
} ;

template < typename dtype > struct fun < dtype , 0 >
{
 int operator()()
 {
  return 42 ;
 }
} ;

int main ( int argc , char * argv[] )
{
 std::cout << fun<float,5>()() << std::endl ;
 std::cout << fun<float,0>()() << std::endl ;
}

1
Потім ви можете використовувати єдиний шаблон функції для здійснення дзвінків, позбувшись потворного ()()синтаксису.
tmr232
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.