константные ссылки в шаблонах c ++ - PullRequest
17 голосов
/ 29 ноября 2011

В шаблоне C ++ с универсальным типом T я могу использовать

const T &

, чтобы получить ссылку на константу T. Однако, если теперь сам T является типом ссылки (например, T = int &), приведенный выше термин разрешается в

int &

а не

const int &

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

const T &

если T сам является ссылочным типом?

Редактировать: пример кода для оценки (компилятор g ++):

template <typename T> class TemplateClass
{
public:
    void foo(const T &bar) { }
};

int main()
{
    TemplateClass<int &> x;
    x.foo(0);   // <-- compile error: no conversion from int to int&
    return 0;
}

Ответы [ 3 ]

22 голосов
/ 29 ноября 2011

Удалить ссылку:

template<typename T>
void Test(const typename std::remove_reference<T>::type & param)
{
        param = 20;
}

Теперь все работает как положено.

10 голосов
/ 29 ноября 2011

Вы всегда можете использовать специализацию шаблона для реализации другой версии для любого вида ссылки:

template <typename T> struct X {
  void foo(T const&);
};

template <typename T> struct X<T&> {
  void foo(T const&);
};

Теперь X<int>::foo ожидает int const& и X<int&>::foo ожидает int const& тоже.

Однако из вашего вопроса не совсем ясно, что именно вы пытаетесь сделать.


Редактировать: Моя версия g ++ (4.6.1) не жалуется без специализации на шаблон для следующего

int i = 7;
X<int&>(i);

В то время как это для

X<int&>(7);

Что является правильным IMO, потому что вы пытаетесь преобразовать временную (7) в изменяемую ссылку (даже если это ссылка на константную ссылку).


Редактировать 2: Если вы хотите уменьшить дублирующийся код, не специализируйте свой исходный класс, а используйте это:

template <typename T> struct R {
  typedef T& Ref;
  typedef T const& ConstRef;
};

template <typename T> struct R<T&> {
  typedef T& Ref;
  typedef T const& ConstRef;
};

template<typename T> struct X {
  void foo(typename R<T>::ConstRef x);
};
1 голос
/ 31 декабря 2012

Я столкнулся с той же проблемой. Кажется, что оператор преобразования типа '&' связывает сильнее, чем квалификатор 'const'. Поэтому, когда у нас есть этот код:

template<class t>
void fun(const t i)
{
}

fun<int&>();

функция заканчивается с типом void (int &) , а не ожидаемым void (const int &) .

Чтобы решить эту проблему, я определил этот шаблон:

template<class t> struct constify { typedef t type; };
template<class t> struct constify<t&> { typedef const t& type; };

Теперь определите вашу функцию как:

template<class t>
void fun(typename constify<t>::type i)
{
}

fun<int&>();

Созданная функция будет иметь тип void (const int &) , если необходимо.

...