Я недавно обновил компилятор gcc с версии 5 до 8, и он сломал наш производственный код. Упрощенная версия сломанного кода включена ниже:
#include <utility>
// Imagine this has several template parameters not just Id and
// this class provides lots of friend functions for retrieving
// all this "metadata". Just one is implemented in this example.
template <typename Tag, unsigned Id>
class MetadataImpl
{
template <typename T, typename U>
using matches =
typename std::enable_if<std::is_same<T, U>::value>::type;
template <typename _Tag, typename = matches<_Tag, Tag>>
friend unsigned GetId(Tag* = nullptr)
{ return Id; }
};
// Let's generate some instances...
template class MetadataImpl<int, 1>;
template class MetadataImpl<double, 2>;
// And a simple test function.
unsigned test()
{
return GetId<int>();
}
Проще говоря, этот код обеспечивает способ захвата метаданных вокруг тега (тип в приведенном выше примере, но также может быть значением enum
) и был первоначально закодирован около 10+ лет назад и видел много gcc обновления, но что-то «сломалось» в gcc 6 (проверено с помощью известного онлайн-компилятора godbolt).
Вполне возможно, что этот код не был поддержан стандартом c ++ и был просто расширением gcc, которое теперь было удалено, но мне было бы интересно узнать, так ли это на самом деле и для чего может быть обоснование это отклонено стандартом.
Кажется также, что clang также не поддерживает этот код, но я заметил, что если вы выполняете ast-dump (clang -Xclang -ast-dump
), то clang, по крайней мере, содержит определения этих функций-друзей, но кажется, что невозможно найти их при использовании (ошибка вывода аргумента шаблона?).
Я был бы очень рад узнать о любом обходном пути или альтернативе, которые работают настолько похожим образом, насколько это возможно, т.е. хотя бы в некоторой форме единственная строка создания экземпляров и, что очень важно, только для тегов, которые имеют был явно создан.
В частности, я не хочу иметь строку шаблонных функций, которые должны быть реализованы в каждом теге (я только что показал один элемент метаданных, и в рабочем коде их много). некоторые из которых получают дополнительную информацию из комбинаций аргументов шаблона и / или другой информации типа). Разработанное выше оригинальное решение привело к созданию очень чистого, расширяемого и обслуживаемого кода. Оборачивать все это в какой-то сложный макрос было бы абсолютно худшим сценарием!
Здесь есть аналогичный вопрос и ответ здесь , но я не могу понять, как заставить это решение работать в этом сценарии, поскольку аргумент функции friend - это не сам родительский класс, а аргумент шаблона об этом.
Изменение функции GetId
на MetadataImpl<...>
в качестве аргумента не будет жизнеспособным решением, поскольку использование функций становится совершенно нецелесообразным. Места, из которых вызываются функции, просто хотят предоставить сам тег.
Заранее спасибо за любую помощь!