AUTOSAR C++14 Rule A14-8-2

Явные специализации шаблонов функций не должны использоваться

Описание

Управляйте определением

Явные специализации шаблонов функций не должны использоваться.

Объяснение

Явная специализация шаблонов функций может вызвать неожиданные проблемы с разрешением перегрузки на C++. Разрешение перегрузки:

  • Первые поиски нешаблона, простая функция, которая имеет соответствующий список параметров.

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

  • После того, как шаблон функции выбран, компилятор ищет подходящую специализацию шаблона.

Специализация шаблона не изменяет порядок процесса разрешения перегрузки, который может привести к запутывающему и неожиданному поведению. Рассмотрите фрагмент кода:

//(a) base template
template<class T> void f( T ); 

//(b) specialization of (a)
template<> void f<>(int*);
//...

//(c) overloads (a)
template<class T> void f( T* );

//...
main(){
	int *p; 
	f( p );
}
Когда f() вызван int* в main(), вы можете ожидать специализацию для int*, отмеченный (b), чтобы быть названным. Компилятор разрешает вызов f() можно следующим образом:

  1. Компилятор ищет простую функцию с входным типом int*.

  2. Поскольку нет такой функции, компилятор ищет шаблон функции, который имеет самый близкий список параметров соответствия.

  3. Шаблон (c), который берет типовой указатель, как введено, является самым близким соответствием для f(int*).

  4. Шаблон (c) не специализирован. Процесс разрешения перегрузки останавливает и вызывает шаблон в (c).

Даже при том, что специализированный шаблон для int* вход типа задан в (b), перегрузка решает к шаблону в (c) вместо этого, который может быть неожиданным.

Когда вы специализируете шаблон перегруженной функции, процесс разрешения перегрузки может стать более сбивающим с толку. То, которое среди перегруженных шаблонов специализировано, зависит от порядка объявления. Рассмотрите фрагмент кода:

//(a)
template <typename T> void F1(T t){}
//(b)
template <typename T> void F1(T* p){}
//(x): Specialization of template
template <> void F1<>(uint16_t* p){}
Вы не можете определить, специализируется ли (x) (a) или (b) от одного только объявления. это зависит от порядка объявления. Например, в предыдущем случае (x) специализируется (b). Но в этом случае, (x) специализируется (a):
//(a)
template <typename T> void F1(T t){}
//(x): Specialization of template
template <> void F1<>(uint16_t* p){}
//(b)
template <typename T> void F1(T* p){}

Чтобы постараться не путать код и неожиданное поведение, постарайтесь не специализировать шаблоны функций. Если необходимо специализировать шаблон функции, то запишите один шаблон функции, который делегирует к шаблону класса. Например, в этом коде, шаблоне функции f() делегаты в классе f_implementation.

template<class T> class f_implementation;

template<class T> void f( T t ) {
	FImpl<T>::f( t ); //Don't specialize function template
} 

template<class T> class f_implementation { 
	static void f( T t ); // Specializing class templates is permissible. 
}
Делегирование к шаблону класса также включает частичную специализацию.

Реализация Polyspace

Если вы явным образом специализируете шаблон функции, Polyspace® отмечает шаблон функции.

Поиск и устранение проблем

Если вы ожидаете нарушение правила, но не видите его, обратитесь к Кодированию Стандартных Нарушений, Не Отображенных.

Примеры

развернуть все

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

#include <cstdint>
#include <memory>
#include <iostream>
//(a)
template <typename T> void F1(T t){
  std::cout << "(a)" << std::endl;
}
//(x) specializes (a)
template <> void F1<>(uint16_t* p){// Noncompliant
  std::cout << "(x)" << std::endl;
}
//(b) overloads (a)
template <typename T> void F1(T* p){// Compliant
  std::cout << "(b)" << std::endl; 
}
//(y) specializes (b)
template <> void F1<>(uint8_t* p){// Noncompliant
  std::cout << "(c)" << std::endl; 
}
//(d) plain old function overloads (a) and (b)
void F1(uint8_t* p){                    // Compliant
  std::cout << "(d)" << std::endl; 
}

int main(void)
{
	auto sp8 = std::make_unique<uint8_t>(3);
	auto sp16 = std::make_unique<uint16_t>(3);
	F1(sp8.get()); //calls (d), might expect (y) 
	F1(sp16.get()); //calls (b), might expect (x)
	return 0;
}

Когда функциональный F1() призван основной, разрешение перегрузки определяет который экземпляр F1() называется.

  • Когда F1 () вызывается с указателями на uint8_t, компилятор вызывает простую функцию (d), потому что это более приоритетно. Вы можете неправильно ожидать, что специализация (y) будет названа.

  • Когда F1 () вызывается с указателями на uint16_t, компилятор вызывает перегруженный шаблон (b), потому что это - самый близкий шаблон соответствия. Вы можете неправильно ожидать, что специализация (x) будет названа.

Специализация шаблонов функций может вызвать беспорядок и неожиданные результаты. Polyspace отмечает специализированные шаблоны функций (x) и (y).

Проверяйте информацию

Группа: шаблоны
Категория: необходимый, автоматизированный
Введенный в R2020a