Ответ 1
Я скопировал ваш первый код в Visual Studio 2015 (он скомпилирован успешно). Я добавил несколько выходов через std::cout
, где я обнаружил, что использование b
дает ошибку компилятора: uninitialized local variable 'b' used
. a
, с другой стороны, был успешно напечатан, когда b
не использовался. Таким образом, казалось бы, С++ немного затрудняет доступ к статическим членам шаблона, как вы сказали, требуя, чтобы вы ссылались на его полное, квалифицированное имя.
Возможно, более любопытными являются следующие строки:
std::cout << example::var<int> << "a\n";
Вышеприведенная строка работает, как ожидалось, вывод 1.5
усечен до 1
и 'a'
с новой строкой. Ни о чем не писать.
std::cout << obj.var<int> << "b\n";
Теперь здесь, где это становится интересным... Не только вышеприведенная строка не распечатывает значение для obj.var<int>
, а 'b'\n
никогда не печатается. Я даже тестировал функции std::cout
good()
fail()
и bad()
, ни одна из которых не сообщала, что что-то не так (и дальнейшее использование std::cout
было успешно выполнено).
Другая странность, которую я обнаружил, заключалась в том, что auto x = obj.var
является законным и подходит для поиска, x имеет тип example
. Теперь, делая это с помощью глобальной переменной шаблона, возникает ошибка компилятора (как и ожидалось, первая из них):
template<typename T> constexpr T ex = 1.5;
auto x = ex // compiler error: argument list for variable template "ex" is missing
Кроме того, я обнаружил, что доступ var
к другой статической функции шаблона был успешным, что еще раз подразумевало, что выбор члена просто не работает в этом случае
class example
{
public:
template <class T> static constexpr T var = T(1.5);
template <typename T> static void thing()
{
std::cout << var<T> << '\n'; // works
std::cout << example::var<T> << '\n'; // also works
}
};
Теперь, насколько стандарт идет, я склонен полагать, что их фразировка немного... педантична. Секции, которые вы указали из стандарта:
нет необходимости использовать синтаксис доступа к члену класса (5.2.5) для ссылки на статический член.
и
Шаблон переменной в области класса представляет собой шаблон статических данных.
казалось бы, подразумевает, что это сработает. Я считаю, что точка, в которой эти кавычки не применяются в этом случае, заключается в том, что шаблон (чего-либо) на самом деле не существует, пока он не будет создан в компиляционной единице (то есть, почему код для шаблонов часто включается в сам файл заголовка).
Из-за этого, хотя переменная шаблона может быть членом класса, его экземпляры не... по какой-то причине... и поэтому требуют оператора разрешения области, а не оператора выбора элемента.
Но ИМО, обращаясь к статическим данным через оператор выбора членов, является плохой практикой, поскольку статические данные и функции фактически не являются частью данного объекта. Доступ к статическим данным так же, как нестатические данные, может привести к тому, что относительно невинно выглядящий код действительно будет ошибочной логикой. Например, если по какой-то причине у вас был неконстантный статический член с именем something
, вы могли бы написать example_object.something = 42
, не ожидая, что что-либо изменится для всех других экземпляров этого класса во всей вашей программе (те же проблемы, что и глобальные переменные, на самом деле). Из-за этого (и тот факт, что синтаксис доступа к членству, по-видимому, не работает для статических переменных-членов шаблона), я рекомендую всегда использовать разрешение области для доступа/изменения статического содержимого вне класса. example_class::something = 42
намного понятнее, что мы меняем something
на все экземпляры example_class
. На самом деле, некоторые более современные языки, такие как С#, требуют доступа к статическим данным через имя класса, если вы не находитесь внутри указанного класса.
Учитывая, что несколько компиляторов являются ошибками для разных частей этой маленькой примерной программы, я бы согласился поспорить, что это не очень хорошо отражено в стандарте (и, вероятно, не используется очень часто на практике), а компиляторы просто обрабатывают его по-другому (другая причина, чтобы избежать этого).
TL;DR
По-видимому, в то время как синтаксис выбора элементов работает для статических переменных-членов, он не работает для статических переменных-членов шаблона (хотя компилятор, похоже, не жалуется). Однако синтаксис разрешения разрешения действительно работает, и IMO должно быть предпочтительным в любом случае.