Правила частичной специализации шаблонов с нетиповыми параметрами

#c #templates #generics

Вопрос:

Рассмотрим следующий шаблон

 template <typename T, int v> void func(const Tamp;x);
 

и я хочу специализироваться на нем для какого-нибудь класса A . Вот моя попытка (со ссылкой на это):

 template <int v> void func<A, v>(const Aamp;x);
 

Однако это незаконно. Мой вопрос в том, почему это незаконно (какое правило это нарушает), и если это противоречит грамматике, есть ли для нас другие способы его специализации A ?

Комментарии:

1. вы можете сделать template <int v> void func(const Aamp;x);

2. @appleapple Но разве это не создание другого шаблона?

3. в чем разница? можете ли вы показать, как вы хотели бы его использовать?

4. Вы не можете частично специализировать функции . См. раздел Шаблоны : «частичная специализация допускается только для шаблонов классов [и шаблонов переменных (начиная с C 14)]».

5. Кстати, лучше изменить порядок параметров шаблона T в соответствии с выводимым: template <int v, typename T> void func(const Tamp;x); разрешить такие вызовы, как func<42>(my_obj);

Ответ №1:

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

 #include <iostream>
class A 
{
    
};

template <typename T, int v> void func(const Tamp;x) //primary template
{
    std::cout<<"primary template"<<std::endl;
}
//this is an overload and not a specialization. Also partial specialization cannot be done for function templates
template <int v> void func(const Aamp;x)
{
    std::cout<<"overload not specialization"<<std::endl;
}
int main()
{
    func<int, 5>(84); //uses primary template 
    
    func<5>(A()); //uses the overloaded version
    return 0;
}
 

Ответ №2:

Шаблоны функций не могут быть частично специализированными, поэтому возникает ошибка:

 <source>:8:23: error: non-class, non-variable partial specialization 'func<A, v>' is not allowed
    8 | template <int v> void func<A, v>(const Aamp;x);
      |                       ^~~~~~~~~~
 

Вы можете, например, частично специализировать тип с помощью operator() :

 template <typename T, int v>
struct func{
    void operator()(const Tamp;x);
};

struct A {};

template <int v> 
struct  func<A, v>{
    void operator()(const Aamp;x);
};
 

Комментарии:

1. Спасибо вам за этот ответ! Я также подумал о возможности использования функционального объекта, и я попробую это сделать!

Ответ №3:

Для этого можно использовать ограничение (или SFINAE).

 #include <iostream>
class A {};
class B {};

template <typename T, int v> void func(const Tamp;)
{
    std::cout<<"generic";
}

template <typename T, int v> void func(const Tamp;)
requires std::is_same_v<T,A>
{
    std::cout<<"A";
}

int main(){
    func<A,1>(A{}); // output A
}
 

https://godbolt.org/z/YcxeoofYE

Ответ №4:

Поймите v , здесь не выводится, что может вызвать нежелательный эффект, оставьте это здесь, так как это может быть полезно для кого-то, кто ответит на этот вопрос.

вы можете сделать это с помощью

 template <typename T, int v> void func(const Tamp;x);
template <int v> void func(const Aamp;x);
 

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

 template <typename T> void func(const Tamp;x);
template <typename T> void func(const T*x);
void func(const Aamp;);
 

уже является допустимой функцией «специализация». не совсем специализация в смысле стандартной формулировки

Комментарии:

1. Вы ошибаетесь. Последние 2 версии, которые вы называете специализацией, являются перегрузками.

2. @AanchalSharma Я не называю их специализацией, поэтому я цитирую их и использую курсив

3. is already a valid function "specialization". Мне кажется, вы называете их специализацией. Может быть, вы сможете более четко сформулировать, что вы имеете в виду, чтобы не было путаницы.

4. @AanchalSharma добавил.