Почему эта переменная шаблона приводит к предупреждению компилятора?

#c #templates #clang #compiler-warnings #c 14

#c #шаблоны #лязг #предупреждения компилятора #c 14

Вопрос:

Почему я получаю это предупреждение от Clang? Мне кажется, что это разумное использование шаблонной константы.

warning: variable 'M_PI<int>' has internal linkage but is not defined [-Wundefined-internal]

 #include <iostream>

template <typename T>
constexpr T M_PI = T(3.1415926535897932);

template <typename T>
constexpr T CalcCircumference(T d)
{
    return d * M_PI<T>;
}

int main()
{
    std::cout << CalcCircumference(42.0f);
}
 

Редактировать: по-видимому, минималистичный тестовый пример сбивает с толку некоторых. Я немного приукрасил это, чтобы, надеюсь, облегчить это.

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

1. @hvd Этот код возвращает постоянное значение из main , так что, конечно , это бессмысленно, но становится менее бессмысленным из-за того, что он кажется достаточно простым, и все же он выдает предупреждение, и я хотел бы знать, почему.

Ответ №1:

Я думаю, вам следует просто проигнорировать предупреждение и пока вообще избегать переменных шаблонов.

Рассмотреть

 template <typename T> T var = 0;
int main() { return var<int>; }
 

Это компилируется без предупреждений, ссылок и выполняется для возврата нуля.

 template <typename T> T var = 0;
template <typename T> T func() { return var<T>; }
int main() { return func<int>(); }
 

Это компилируется без предупреждений, но не связывает: выдает сообщение об ошибке.

$ clang   test2.cc -o test2 -std=c    1y -pedantic -Wall
/tmp/test2-736968.o:test2.cc: функция int func(): ошибка: неопределенная ссылка на 'var'
clang: ошибка: команда компоновщика завершилась ошибкой с кодом выхода 1 (используйте -v длясм. Вызов)

Принудительное создание явного экземпляра действительно работает:

 template <typename T> T var = 0;
template int var<int>;
template <typename T> T func() { return var<T>; }
int main() { return func<int>(); }
 

Я бы сказал, что это показывает, что реализация переменных шаблонов в clang является неполной. Ваше использование constexpr просто делает так, что clang обнаруживает свою собственную незавершенную реализацию.

Ответ №2:

Это была ошибка (поданная как PR19305) в более ранних версиях Clang. См. Также PR19571 и PR17846, которые были разными ошибками с похожими симптомами. Все это исправлено в Clang 3.5.