Является ли создание шаблона частью синтаксического анализа C ++ - PullRequest
4 голосов
/ 29 апреля 2020

У меня была с кем-то дискуссия о разборе C ++. Он сказал, что C ++ должен создавать экземпляры всех шаблонов при анализе, хотя я думал, что это не так. Вы можете просто создать дерево разбора и затем создать экземпляр шаблона позже.

Как G CC и Clang справляются с этим?

1 Ответ

3 голосов
/ 29 апреля 2020

Ваш друг прав. Шаблоны Tbe должны быть созданы, и это то, что делают компиляторы. [Примечание 1]

Есть гораздо более простые примеры, но у меня был один удобный; оно взято из этого ответа .

Разбор первой строки в main зависит от реализации (а не только разбор) шаблона IsPrime. Как написано, он генерирует синтаксическую ошибку, если аргумент шаблона для IsPrime не является простым; однако изменение () на (0) позволит обеим функциям быть действительными, но с очень разным анализом. (С составным аргументом шаблона typen - это простая целочисленная константа, а typen<1>(0) - это два сравнения, эквивалентные (typen < 1) > 0.)

Не все примеры являются такими же надуманными, как этот. Когда я писал это, я пытался подчеркнуть другую точку зрения: правильный синтаксический анализ программы на C ++ может потребовать решения довольно сложной математической задачи, например, определения, является ли большое число простым. Это выводит C ++ далеко за пределы области контекстно-свободных языков.

template<bool V> struct answer { answer(int) {} bool operator()(){return V;}};

template<bool no, bool yes, int f, int p> struct IsPrimeHelper
  : IsPrimeHelper<p % f == 0, f * f >= p, f + 2, p> {};
template<bool yes, int f, int p> struct IsPrimeHelper<true, yes, f, p> { using type = answer<false>; };
template<int f, int p> struct IsPrimeHelper<false, true, f, p> { using type = answer<true>; };

template<int I> using IsPrime = typename IsPrimeHelper<!(I&1), false, 3, I>::type;
template<int I>
struct X { static const int i = I; int a[i]; }; 

template<typename A> struct foo;
template<>struct foo<answer<true>>{
  template<int I> using typen = X<I>;
};
template<> struct foo<answer<false>>{
  static const int typen = 0;
};

int main() {
  auto b = foo<IsPrime<234799>>::typen<1>(); // Syntax error if not prime
  return 0;
}

Заметки

  1. Ира Бакстер скажет, что вы можете использовать парсер GLR, чтобы найти все возможный альтернативный анализ без создания экземпляров шаблонов, а затем выберите правильный анализ после создания экземпляра. Это правда, но ИМХО разбор не закончился, пока вы не знаете, какой синтаксический анализ правильный.
...