2016-01-21 3 views
1

Когда я объявляю шаблонный класс, я могу использовать любые аргументы шаблона не типа в constexpr функций-членов, таких, как это:функция член Constexpr возвращает параметр шаблона не считается constexpr при доступе через ссылку

template <int Value> 
struct Foo { 
    constexpr int value() const { return Value; } 
}; 

затем я могу использовать эту функцию позже инициализировать constexpr переменные следующим образом:

template <int Value> 
void use_value(Foo<Value> foo) { 
    constexpr int baz{ foo.value() }; 
} 

int main() { 
    Foo<10> bar; 
    use_value(bar); 
} 

то, что я не понимаю, что когда я беру foo по ссылке ...

template <int Value> 
void use_value(Foo<Value>& foo) {  // by ref 
    constexpr int baz{ foo.value() }; 
} 

int main() { 
    Foo<10> bar; 
    use_value(bar); 
} 

... clang скажет мне, что foo.value() не является постоянным выражением!

test.cpp:8:24: error: constexpr variable 'baz' must be initialized by a constant expression 
    constexpr int baz{ foo.value() }; 
        ~~^~~~~~~~~~~~~ 
test.cpp:13:5: note: in instantiation of function template specialization 'use_value<10>' 
     requested here 
    use_value(bar); 

Почему это происходит? Имеет ли он какое-то отношение к факту, что в первом примере компилятор смог следить за всем временем жизни foo, тогда как при взятии по ссылке какая-то другая часть программы могла бы изменить экземпляр, как-то влияя на constexprness foo.value() ? Хотя здесь явно не так (учитывая специализацию шаблона, нет возможности изменить значение Value), я не уверен, действительно ли вы могли бы «разрушить» функции constexpr-члена, вмешавшись в экземпляр в середине его исполнение в некоторых случаях.

Редактировать

Хорошо, так что ссылки плохо для constexpr, так как они имеют место во время выполнения - и значения constexpr жестко закодированы в результате исполняемый файл. Как насчет постоянной ссылки? Это работает:

int main() { 
    constexpr int foo2{5}; 
    int const& bar2{ foo2 }; 
} 

Но с Foo класса, это не поможет изменить ссылку на const:

template <int Value> 
void use_value(Foo<Value> const& foo) { // const ref 
    constexpr int baz = foo.value(); 
} 

я получаю ту же ошибку компилятора. В чем тут разница?

+0

Если 'Foo :: value' должно возвращать' значение', вы должны просто его создать, а затем использовать эту статическую функцию в 'use_value' (и полностью отбросить параметр foo). – Rumburak

+0

Согласен, это просто глупый пример, чтобы продемонстрировать, что я имею в виду. Он не пытается понять смысл программирования. – user1685094

+0

Ну, в конце концов, ссылка - это просто указатель со слегка отличающейся семантикой. Для 'constexpr' вам нужны значения ... – Rumburak

ответ

1

Что-то прошло по ссылке не может быть constexpr. И для того, чтобы функция фактически использовалась как constexpr, все аргументы и объекты, используемые в этой функции, также должны быть constexpr. Теперь, поскольку ссылка (даже объекта шаблона) может никогда не быть constexpr, это означает, что лучший выбор заключается в том, чтобы компилятор мог выбросить ошибку и дать разработчику знать, а не альтернативу, constexpr версия функции.

Это потому, что ссылка означает, что у нее должно быть место памяти во время работы (см. C++ 11 rvalue и lvalue, а также ссылки rvalue). Если что-то квалифицируется как constexpr, это означает, что оно известно только и используется во время компиляции, и результат выпекается в результирующий исполняемый файл так же, как жестко закодированные числа или строки.

РЕДАКТИРОВАТЬ:

Постоянная ссылка (Const &) по-прежнему является ссылкой. const & действует как определитель аргументов, аналогичный регулярной ссылке и по-прежнему требует места памяти во время выполнения - объекты const & должны ссылаться на другой объект.См. What is a constant reference? (not a reference to a constant)

В вашем примере const & зависит от constexpr, который является точным. Если constexpr зависит от константы &, это не сработает.

+0

Почему downvote? Разве это не правильный ответ? –

+0

В этом случае это не значение constexpr, которое передается по ссылке, а только экземпляр Foo, который содержит код для «вычисления». Я не вижу, как это влияет на фактический вызов функции, поскольку, как вы сказали, константа 10 должна быть «испечена в исполняемый файл» и на самом деле в некотором смысле передана по значению в параметре шаблона. – user1685094

+0

Кроме того, могу ли я взять ссылку на статическую переменную, которая не имеет места памяти во время выполнения? То же самое относится к любой переменной constexpr, не так ли? – user1685094

0

Рассмотрите, почему вы делаете то, что делаете. Почему вы хотите передать constexpr по ссылке в первую очередь? Нет никакой пользы, и это фактически бессмысленно.

Кроме того, int const& не является постоянной ссылкой на int, а скорее ссылкой на const int. Поэтому, когда вы правы, код int const& bar2{ foo2 }, тогда он работает. На самом деле нет такой вещи, как «постоянная ссылка» (но как побочная заметка есть постоянные указатели: int * const).

Итак, вкратце, не делайте Foo<Value>& foo как нет причин для этого. Foo<Value> foo выполняет именно то, что вы хотите и оцениваете во время компиляции.

 Смежные вопросы

  • Нет связанных вопросов^_^