Ответ 1
Похоже, это ограничение было подчинено следующему предложению Разрешить постоянную оценку для всех аргументов шаблона не-типа, все еще пытаясь определить статус этого предложения. В нем говорится:
Синтаксические ограничения для указателей, ссылок и указателей на члены неудобны и не дают разумных рефакторингов. Например:
template<int *p> struct A {}; int n; A<&n> a; // ok constexpr int *p() { return &n; } A<p()> b; // error
и далее говорит:
Историческая причина ограничения была, скорее всего, тем, что С++ ранее не имели достаточно сильной спецификации для константные выражения типа указателя, ссылки или указателя на член. Однако это уже не так. Статус-кво заключается в том, что для оценки такого аргумента шаблона требуется реализация, но должен отбросить результат, если он не будет равен нулю.
В дополнение к вышесказанному ограничение сущностей с привязкой артефакт экспортированных шаблонов и мог быть удален, когда ограничения на привязку к параметрам типа шаблона были удалены.
и он удалит этот раздел примечания с этим ограничением:
неназванные lvalues и имена lvalues без привязки
вся заметка гласит:
Временные, неназванные lvalues и имена lvalues без привязки неприемлемые шаблонные аргументы, когда соответствующие шаблон-параметр имеет ссылочный тип.
Обновить
Пересмотренная версия этого предложения N4268 была принята в рабочий проект в Урбане, и мы можем видеть изменения в последнем рабочем проекте N4296. Новая заметка гласит:
Временной объект не является допустимым аргументом шаблона, если соответствующий шаблон-параметр имеет ссылочный тип
Нормативный раздел 14.3.2
(temp.arg.nontype) paragraph 1
, который с этим предложением сказал бы:
Для шаблона-шаблона, не относящегося к типу ссылки или типа указателя, значение константного выражения не должно упоминаться (или для указателя тип, не должен быть адресом):
- подобъект (1.8),
- временный объект (12.2),
- строковый литерал (2.14.5),
- результат выражения typeid (5.2.8) или
- предопределенная переменная func (8.4.1).
и мы можем найти эту новую формулировку в последнем проекте стандарта N4296.
Похоже, что это изменение действительно реализовано в clang HEAD
, чтобы увидеть, как ваш код работает live, используя флаг -std=c++1z
. Это подразумевает, что изменение должно быть частью С++ 17, если никакие последующие изменения не изменят или не изменят его.