Почему невычитываемые параметры шаблона проблематичны? - PullRequest
0 голосов
/ 29 апреля 2019

Попытка скомпилировать этот фрагмент кода приводит к ошибке.

template <typename T>
struct MyClass;

template <typename T, std::size_t sz>
struct MyClass<T> {
    static void print() {
        std::cout << "Partially specialized" << std::endl;
    }
};

ошибка: параметры шаблона не выводятся при частичной специализации

Попытка сделать это возможнымвыводить sz решает проблему.Например:

template <typename T, std::size_t sz>
struct MyClass<T[sz]> {
    static void print() {
        std::cout << "Partially specialized" << std::endl;
    }
};

Мой вопрос заключается в том, как компилятор интерпретирует такую ​​программу и в чем заключается рациональность, не позволяющая иметь первую структуру?

Дальнейшее уточнение: я думаю, что если бы исходный код был компилируемым, мы могли бы использовать его таким образом: MyClass<int, 4>::print().

Ответы [ 2 ]

1 голос
/ 29 апреля 2019

Я думаю, что если бы исходный код был компилируемым, мы могли бы использовать его таким образом: MyClass<int, 4>::print().

Это не так, как работает специализация шаблона.Если вы объявите базовый шаблон как template <class T> struct MyClass, то экземпляр MyClass может быть создан только с одним параметром типа шаблона.Его нельзя создать как MyClass<int, int> или MyClass<int, 3> или MyClass<3>.

Специализация шаблона может просто специализироваться на параметрах базового шаблона.

Возвращаясь к вашемупроблема.Таким образом, MyClass может быть создан следующим образом: MyClass<int>, MyClass<float>, MyClass<SomeClass>, MyClass<int*>, MyClass<int[10]> и т. Д. И т. П.

Когда вы пишете

template <typename T, std::size_t sz>
struct MyClass<T[sz]> { 

Вы специализируете шаблон MyClass<T> для любого T, который является массивом или любого типа любого размера.Например, MyClass<int[24]> будет использовать эту специализацию.

Когда вы пишете

template <typename T, std::size_t sz>
struct MyClass<T> {
//             ^
//             no sz here

Это похоже на специализацию MyClass, но это не так, потому что sz не появляется впараметры специализации.

1 голос
/ 29 апреля 2019

В C ++, после того как мы объявим шаблон, мы можем специализировать его, если захотим, например ::

template <typename T> foo;
template <typename U> foo<U*>;

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

Таким образом, если вы посмотрите на сообщения об ошибках , другие компиляции дадут вам :

(лязг:)

<source>:7:8: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list
struct MyClass<T> {
       ^      ~~~
<source>:6:1: error: too many template parameters in template redeclaration
template <typename T, std::size_t sz>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(MSVC:)

<source>(11): error C2753: 'MyClass<T>': partial specialization cannot match argument list for primary template
<source>(11): error C2764: 'sz': template parameter not used or deducible in partial specialization 'MyClass<T>'

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

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

template <typename U, std::size_t sz>
struct MyClass<U[sz]> {
    static void print() {
        std::cout << "Partially specialized" << std::endl;
    }
};

, поэтому специализация - это когда T имеет форму U[sz].

...