Непонимание специализации и констант шаблонов C ++

Я пытаюсь осмыслить специализацию шаблона и немного запутался (возможно, не понимаю, что такое typename на самом деле или чего ожидает компилятор)

Пример 1 (компилируется):

template <typename A, typename... Args>
class Example
{
public:
    Example(){}
    virtual ~Example(){}
};

template <typename A, typename... Args>
class Example<A, int, Args...>{
    Example(){}
    virtual ~Example(){}
};

Пример 2 (компилируется):

template <typename A, int, typename... Args>
class Example
{
public:
    Example(){}
    virtual ~Example(){}
};

template <typename A, typename... Args>
class Example<A, 2, Args...>{
    Example(){}
    virtual ~Example(){}
};

Пример 3 (сбой):

template <typename A, typename... Args>
class Example
{
public:
    Example(){}
    virtual ~Example(){}
};

template <typename A, typename... Args>
class Example<A, 2, Args...>{
    Example(){}
    virtual ~Example(){}
};

Ошибка:

ошибка: несоответствие типа / значения в аргументе 2 в списке параметров шаблона для «Пример класса шаблона

Вопросы:

Во-первых, я новичок в общем программировании и надеюсь, что задаю правильные вопросы. Терминология спецификации компилятора все еще немного чужда мне.

  • Что случилось? Компилятор пытается рассматривать константу как имя типа?
  • Если typename может быть специализирован как int, а int может быть специализирован как 2, почему типовое имя не может быть специализировано как 2?
  • Что было бы «правильным» методом для специализации класса с помощью int или enum?
  • Я задаю правильные вопросы?

Спасибо

ИЗМЕНИТЬ / Решение:

После того, как я понял, что происходит (из объяснения Якка), вот как выглядит мое окончательное решение. Я где-то читал одного из гуру C ++, что «Вы можете решить любую проблему, добавив еще один уровень абстракции». Теперь я знаю, что это значит: D

 enum ETypes
{
    UNKNOWN = 0,
    INT = 1,
    FLOAT = 2,
    STRING = 3,
    FUNC = 4,
};

// This is to use the ETypes as a type.
// Note that T is not a type, hence use it as RHS
template<ETypes T>
class ETypeName
{
public:
    ETypes type = T;
};


// The example
template <typename A, typename... Args>
class Example
{
private:
    Example();              // Hide the constructor as private
                            // to generate compilation error
    virtual ~Example(){}
};


// LOOK! We can use the Enum to specialize the class.
template <>
class Example<ETypeName<ETypes::INT>>{
public:
    ETypes mType;
    Example():mType(ETypes::INT){}
    virtual ~Example(){}
};

И в main ():

    Example<ETypeName<ETypes::INT>> x;

    // This can't happen. Private constructor. Not specialized yet
//  Example<ETypeName<ETypes::FLOAT>> x1;

person Makketronix    schedule 07.02.2017    source источник
comment
Параметры шаблона, не являющиеся типом, отличаются от параметров шаблона типа. По сути, да, 2 рассматривается как параметр, не относящийся к типу, но класс шаблона ожидает тип.   -  person user975989    schedule 07.02.2017
comment
Ах, так это то, что мне не хватало   -  person Makketronix    schedule 07.02.2017


Ответы (2)


Первичная специализация выглядит так:

template <typename A, typename... Args>
class Example

Когда вы вводите Example<stuff goes here>, он всегда сопоставляется со списком аргументов <typename A, typename... Args> основной специализации.

Это совсем другой зверь:

template <typename A, typename... Args>
class Example<A, int, Args...>

Это второстепенная специализация. Здесь,

template <typename A, typename... Args>

является не списком аргументов, а скорее списком вычетов.

Список аргументов:

class Example<A, int, Args...>

здесь. То, что находится между <>, используется только для сопоставления с образцом аргументов, переданных в основную специализацию.

Типы и параметры шаблона, не являющиеся типами, - это разные вещи. Основная специализация детализирует, какие аргументы являются типом, а какие нет.

После сопоставления с основной специализацией каждая из дополнительных специализаций сопоставляется по образцу с аргументами. Каждый жизнеспособный кандидат исследуется, и используется достаточно сложная система, чтобы определить, какой из них «более специализированный», правила которой я здесь не буду вдаваться.

person Yakk - Adam Nevraumont    schedule 07.02.2017
comment
Я принимаю это как ответ для разъяснения определений и терминологии и объяснения того, как они работают на более глубоком уровне, с которым я не сталкивался. - person Makketronix; 07.02.2017

Что случилось? Компилятор пытается рассматривать константу как имя типа?

да.

Если typename может быть специализирован как int, а int может быть специализирован как 2, почему типовое имя не может быть специализировано как 2?

Параметр шаблона, начинающийся с typename, требует в качестве аргумента типа. Во втором примере второй параметр шаблона - int, а не typename something. Таким образом, он ожидает не тип в качестве аргумента, а фактическое значение int.

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

Что было бы «правильным» методом для специализации класса с помощью int или enum?

Не уверен, что правильно понимаю смысл вопроса. Правильный способ специализации вашего шаблона для экземпляров с использованием int второго параметра шаблона - это ваше второе определение шаблона.

person franmon    schedule 07.02.2017