В общем, эта неприятная проблема с шаблонами должна требовать дублирования, потому что семантика, в которой переменная является константной или нет, или ссылкой, или нет, довольно различна.
Решение C ++ 11 для этого - "decltype", но это плохая идея, потому что все, что он делает, это составная и уже сломанная система типов.
Независимо от того, что говорит Стандарт или Комитет, «const int» не является и никогда не будет типом. Также «int &» никогда не будет типом. Поэтому параметр типа в шаблоне никогда не должен связываться с такими нетипами, и, к счастью, это так. К сожалению, вы все еще можете явно форсировать эту беспринципную замену.
Существуют некоторые идиотские правила, которые пытаются «исправить» эту проблему, например, «const const int» сводится к «const int», я даже не уверен, что произойдет, если вы получите «int & &»: помните даже Стандарт не считает "int &" типом, есть тип "int lvalue", но он отличается:
int x; // type is lvalue int
int &y = x; // type is lvalue int
Правильное решение этой проблемы на самом деле довольно просто: все является изменяемым объектом. Выкиньте «const» (это не так уж полезно) и отбросьте ссылки, lvalues и rvalues. Совершенно очевидно, что все типы классов являются адресуемыми, rvalue или нет (указатель «this» является адресом). Комитет предпринял тщетную попытку запретить присваивать и обращаться к значениям ... дело по делу работает, но его легко избежать с помощью тривиального броска. Регистр присваивания не работает вообще (поскольку присваивание является функцией-членом, а значения r не являются константными, вы всегда можете присвоить типу значение типа rvalue).
Так или иначе, в толпе метапрограммирования шаблонов есть «decltype», и с этим вы можете найти кодировку объявления, включающую любые биты «const» и «&», и затем вы можете разложить эту кодировку, используя различные операторы библиотеки. Этого нельзя было сделать раньше, потому что эта информация на самом деле не является информацией о типе («ref» - это фактически информация о распределении памяти).