Почему `const T &` не обязательно будет const? - PullRequest
0 голосов
/ 01 февраля 2019
template<typename T>
void f(T a, const T& b)
{
    ++a; // ok
    ++b; // also ok!
}

template<typename T>
void g(T n)
{
    f<T>(n, n);
}

int main()
{
    int n{};
    g<int&>(n);
}

Обратите внимание: b имеет значение const T& и ++b в порядке!

Почему const T& не обязательно будет константой?

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Я знаю, что уже есть принятый ответ, который является правильным, но просто добавить к нему немного, даже за пределами области шаблонов и просто в объявлениях функций в целом ...

( const T& ) 

это не то же самое, что

( const T )

В вашем примере, который соответствует первому, у вас есть константная ссылка.Если вам действительно нужно постоянное значение, которое нельзя изменить, удалите ссылку, как во втором примере.

0 голосов
/ 01 февраля 2019

Добро пожаловать в const и ссылка сворачивается .Когда у вас есть const T&, ссылка применяется к T, как и const.Вы звоните g как

g<int&>(n);

, поэтому вы указали, что T - это int&.Когда мы применяем ссылку на ссылку lvalue, две ссылки сворачиваются в одну, поэтому int& & становится просто int&.Затем мы получим правило из [dcl.ref] / 1 , которое гласит, что если вы примените const к ссылке, она будет отброшена, поэтому int& const просто станет int& (обратите внимание, что вына самом деле не может объявить int& const, это должно быть из typedef или шаблона).Это означает, что для

g<int&>(n);

вы на самом деле звоните

void f(int& a, int& b)

и фактически не изменяете константу.


Если бы вы назвали g как

g<int>(n);
// or just
g(n);

тогда T будет int, а f будет помечено как

void f(int a, const int& b)

, поскольку T больше не является ссылкой,const и & будут применены к нему, и вы получите ошибку компилятора при попытке изменить постоянную переменную.

...