Рассмотрим эту программу:
template <int F(), int N = F()>
void f() { }
constexpr int g() { return 1; }
int main() { f<g>(); }
Это действительно? Должны ли компиляторы видеть во время определения шаблона, что F
может потенциально ссылаться на функцию constexpr
, и поэтому аргумент по умолчанию для N
может быть действительным?
gcc и clang принимают это, но Intel 1 отклоняет функцию шаблона во время определения шаблона, потому что F()
не является постоянным выражением. Intel принимает f<g, g()>()
, если аргумент по умолчанию удаляется, поэтому понятно, что g()
можно использовать в постоянном выражении вообще.
Мне непонятно, что говорит стандарт. Ясно, что (С++ 11 [expr.const] p2)
вызов функции, отличной от конструктора
constexpr
для литерала или функцииconstexpr
делает выражение непостоянным, но мне не ясно, применимо ли это здесь. Во время определения шаблона это, безусловно, похоже, применяется, поскольку F
не объявляется функцией constexpr
, но в то же время ошибки во время определения шаблона должны быть диагностированы только в том случае, если нет допустимых создание экземпляра шаблона, и здесь действительно существует действительная копия.
Я могу видеть аргументы для обоих ответов, поэтому я запутался. Есть ли окончательный ответ на этот вопрос?
1. Повторное тестирование с текущей версией компилятора Intel показывает, что он работает очень хорошо, поэтому предположительно разработчики Intel считают его ошибкой и с тех пор исправили его. Это огромный намек на то, что код должен быть действительным. Тем не менее, было бы неплохо получить окончательный ответ, основанный на стандарте.