Что делает этот код "специализации" шаблона и почему он компилируется, но не работает, как ожидалось? - PullRequest
0 голосов
/ 17 февраля 2012

Я пытаюсь специализировать только один метод шаблона класса .

Принятый ответ там определенно работает, но что означает этот код для компилятора и почему он не работает должным образом?

#include <stdio.h>

template <typename T>
struct Node
{
  void split() { puts( "Default method" ) ; }

  // this compiles, but it doesn't appear to do anything!
  template <int> void split() { puts( "Int method" ) ; }
} ;

// This definitely works
//template <> void Node<int>::split() { puts( "Int method" ) ; }

int main()
{
  Node<double> n ;
  n.split() ; // "Default method"

  Node<int> i;
  i.split();  // "Default method" again!
}

Ответы [ 4 ]

4 голосов
/ 17 февраля 2012

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

Чтобы позвонить, вы должны использовать, например ,::1004*

n.split<1>();
3 голосов
/ 17 февраля 2012

Звоните так:

n.split<10>();
i.split<10>(); //or use any constant integral value

Если вы собираетесь вызывать шаблон функции.Обратите внимание, что шаблон функции не является специализацией.Это скорее шаблон первичной функции, и для его вызова необходимо явно указать аргумент шаблона.

Вы можете сделать даже это:

const int x = 100;
i.split<x>(); //ok - x is constant expression

Но это недопустимо:

int y = 100;
i.split<y>(); //error - y is not constant expression
1 голос
/ 17 февраля 2012

Давайте посмотрим на синтаксис для специализации шаблона.Во-первых, вот шаблон

template<typename T> void bar() { std::cout << "generic\n"; }

Теперь, чтобы объявить специализацию, вы должны предоставить другое определение для этого шаблона с параметрами, «заполненными» для шаблона, являющимся специализированным:

void bar<int>() { std::cout << "special for int\n"; }

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

template<>
void bar<int>() { std::cout << "special for int\n"; }

Обратите внимание, что при «заполнении» параметров шаблона конкретные типы помещаются в одно и то же место.как они делают, когда вы используете шаблон, а не внутри template<...>

Вот код из этого другого вопроса о том, как специализировать один член шаблона класса для конкретной реализации объекта.template.

template <typename T>
struct Node
{
  void split() { puts( "Default method" ) ; }
};

template<>
void Node<int>::split() { puts( "Int method" ) ; }

Это то же самое, что и

template <typename T>
struct Node
{
  void split();
};

// A
template<typename T>
void Node<T>::split() { puts( "Default method" ) ; }

// B
template<>
void Node<int>::split() { puts( "Int method" ) ; }

Как видите, B - это специализация A, потому что Node<int> in B заполняетв параметрах A.

Теперь посмотрите на ваш код:

template <typename T>
struct Node
{
  void split() { puts( "Default method" ) ; }

  template <int> void split() { puts( "Int method" ) ; }
};

Здесь никакой специализации нет.Ничто не «заполняет» параметры шаблона для какого-либо другого шаблона.

Так что же означает template<int>?На первый взгляд вы можете подумать, что это означает, что вы «заполняете» некоторые template<typename T> с помощью T = int, но это не так.Когда вы заполняете параметры шаблона для специализации, вы не делаете это внутри template<...>.

Вместо этого template<int> использует что-то, что называется «нетипичные параметры шаблона».В template<typename T> вы создаете шаблон, который может быть создан для разных типов.Например:

template <typename T> void bar();
bar<Foo>();
bar<std::string>();

template<int> - это одно и то же, за исключением того, что позволяет получать разные экземпляры для разных значений int, а не для разных типов.См .:

template <int N> void baz();
baz<1>();
baz<INT_MAX>();

В одном случае параметром шаблона является typename, и поэтому шаблон создается с типами.В другом случае параметр шаблона равен int, и поэтому шаблон создается с значениями int.

Вот пример шаблона, который использует нетипичные параметры шаблона:

template<int N>
struct array{
    double arr[N];
};

array<3> k = {{ 0.0, 0.0, 1.0 }}; // has a member 'double arr[3]'
array<2> j = {{ 0.0, 1.0 }}; // has a member 'double arr[2]'

А вот еще один, где выводится значение N:

template<typename T,int N>
int size_of_array(T (&my_array)[N]) { // N is deduced from the argument you pass size_of_array
    return N;
}

double X[100];
std::cout << size_of_array(X) << '\n'; // instantiates size_of_array<double,100>
0 голосов
/ 17 февраля 2012

В вашем классе теперь есть два разных метода split, один шаблонный, а другой нет. Если вы хотите увидеть вывод метода шаблона, вы должны вызвать его явно.

i.split<1>();

Вернитесь к связанному вопросу, это правильный способ сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...