@Julius: я понимаю, что вы имеете в виду. Я могу привести и другие примеры, которые GCC, похоже, тоже допускает. Я склонен сказать, что они все еще не соответствуют требованиям, о которых я упоминал. Похоже, что существует некоторое противоречие между этим правилом и правилом, определяющим основное константное выражение, которое допускает ссылочный тип, если оно «имеет предшествующую инициализацию и [...] is инициализируется постоянным выражением». Правило, которое я цитировал, должно иметь приоритет.
вопрос кажется связанным ссуществующий, но я не понимаю "портативный обходной путь", представленный вответ там (с привлечениемconst auto this_ = this;
) и более того, я думаю, что следующий пример легче следовать.
Я играю со следующим фрагментом кода C ++ 17 (живое демо):
#include <iostream>
struct Test {
const char* name_{nullptr};
const Test* src_{nullptr};
constexpr Test(const char* name) noexcept
: name_{name}
{}
constexpr Test(const Test& src) noexcept
: src_{&src}
{
name_ = src_->name_;
src_ = nullptr;
}
};
template<char c>
void print_constexpr_char() {
std::cout << c << std::endl;
}
int main() {
constexpr const char* in = "x";
constexpr auto foo = Test{in};
constexpr auto bar = Test{foo};
std::cout << bar.name_ << std::endl;
print_constexpr_char<bar.name_[0]>();
return 0;
}
Сбой компиляции с GCC 7.2, в то время как Clang 5.0.0 не видит никаких проблем. Ошибка GCC по существу читает
ошибка: значение 'bar' нельзя использовать в константном выражении
примечание: «бар» используется в своем собственном инициализаторе
Я еще больше запутался, осознав, что удаление финалаprint_constexpr_char
делает компиляцию кода, хотя он все еще содержит строкуconstexpr auto bar = Test{foo};
на что GCC жаловался («используется в своем собственном инициализаторе»).
constexpr
конструктор как промежуточный этап перед преобразованием строящегося объекта в конечное состояние, которое может быть сохранено вconstexpr
переменная?