Шаблон статической функции и переполнение стека MISRA

Следующий шаблон функции со специализациями должен использоваться в том же .cpp только файл, поэтому я хотел бы сделать это static, Следующий код компилируется (без предупреждений) с использованием MS Visual C ++ 2008 и GCC 4.8.1 и работает как задумано. (Добавление static в начале строк 5 и 11 GCC выдаст ошибку, но не MSVC.)

 1  template <class T>
2  static bool foo(const T param);
3
4  template <>
5  bool foo<int>(const int param)
6  {
7      return doSomethingWithInt(param);
8  }
9
10  template <>
11  bool foo<bool>(const bool param)
12  {
13      return doSomethingWithBool(param);
14  }

Однако, MISRA C ++ checker жалуется:

  • (MISRA2008.3-3-2) Применить ключевое слово static к объявлению ‘foo’ (1)
  • (MISRA2008.3-3-2) Примените статическое ключевое слово к объявлению ‘foo’ (5)
  • (MISRA2008.2-10-5-b) Идентификатор ‘foo’ используется повторно (5)
  • (MISRA2008.3-3-2) Применить ключевое слово static к объявлению ‘foo’ (11)
  • (MISRA2008.2-10-5-b) Идентификатор ‘foo’ используется повторно (11)

Я попытался выяснить, что не так, и нашел подсказку в Стандартная цитата C ++:

Для вызова функции, который зависит от параметра шаблона, если
имя функции является безусловным идентификатором, но не идентификатором шаблона,
Функции-кандидаты находятся с использованием обычных правил поиска (3.4.1,
3.4.2) за исключением того, что:

  • Только для части поиска с использованием поиска без определения имени (3.4.1)
    объявления функций с внешняя связь из шаблона
    Определение контекста найдено.

Означает ли это, что компиляторы отбрасывают static спецификация и нет никакого способа на самом деле сделать шаблоны статических функций в C ++ 03?

3

Решение

Явные специализации позволяют изменять определение функции (или класса) на основе аргументов шаблона, с которыми специализирован шаблон. Они не являются «новыми декларациями».

GCC правильно предупредить за использование static по явным специализациям 7.1.1 / 1:

Спецификатор класса хранения не должен указываться в явной специализации (14.7.3) или в явной директиве создания экземпляра (14.7.2).

Таким образом, кажется, что совет от вашей программы проверки MISRA применять «статический» неверен для 5 и 11, и я также хотел бы спросить, что foo как-то повторно Есть только одна сущность foo это имеет разные определения.

Функция с внутренней связью не видна за пределами этой единицы перевода. Явная специализация рассматривается только после выбора самого основного шаблона с помощью разрешения перегрузки.

Учтите следующее:

template <typename T>
void f (T);              // #1

template <>
void f<int*> (int*);     // #2

template <typename T>
void f (T*);             // #3

void b() {
int * i;
f(i);                  // Calls #3
}

Поиск для f находит два шаблона, № 1 — f(T) и № 3 — f(T*), T выводится int* для № 1 и int для № 3 (14.8.2). Разрешение перегрузки происходит со специализациями # 1 -> f(int*) и № 3 -> f(int*), Это не лучшее совпадение, поэтому имеет место частичное упорядочение (14.5.6.2). Результатом частичного упорядочения является то, что # 3 является более специализированным, чем # 1. Поэтому компилятор выбирает № 3 в качестве лучшего соответствия. NB: Явная специализация не принимала участия ни в одном из вышеперечисленных шагов.

Если бы не было № 3. Тогда # 1 был бы выбран в качестве лучшего соответствия по разрешению перегрузки. Затем компилятор ищет список специальностей. Выведенный список аргументов int* соответствует списку аргументов, используемому в явном specailziation, и поэтому вызывается определение # 2.

Относительно цитируемого абзаца:

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

Это ограничение возникло еще тогда, когда шаблоны можно было экспортировать (C ++ ’03 14/6). Идея состояла в том, чтобы позволить шаблонам быть определенными вне текущей единицы перевода. Это ограничение поиска помогло бы гарантировать, что изменение неэкспортированного шаблона для экспорта не приведет к созданию другой смысловой программы.

Что касается вашего вопроса о том, что это означает для шаблонов статических функций и C ++ ’03, то реальность такова, что только один известный мне поставщик компиляторов когда-либо реализовывал экспортированные шаблоны в полном объеме. В любом случае, есть большая вероятность, что большинство поставщиков компиляторов долгое время следовали советам C ++ 11. С точки зрения соответствия требованиям MISRA, лучший вариант — следовать рекомендациям металла комментарий к вашему вопросу. Поместите шаблон в безымянное пространство имен.

В C ++ ’03 имена будут не вызываться извне модуля перевода, а для C ++ ’11 и далее они неявно имеют внутреннюю связь (3.5 / 4):

Неназванное пространство имен или пространство имен, объявленное прямо или косвенно в безымянном пространстве имен, имеет
внутренняя связь.

0

Другие решения


По вопросам рекламы [email protected]