Является ли этот код шаблона C ++ действительным? G ++ компилирует это, но Clang не будет - PullRequest
2 голосов
/ 29 декабря 2011

Я пытаюсь скомпилировать небольшую программу на c ++, используя clang со стандартной библиотекой C ++ по умолчанию (4.6.2) в Fedora. Сам Clang компилируется нормально, а тестовая программа использует только компиляцию и работает нормально.

Моя другая программа использует веревки, на которые жалуется кланг.

/ USR / Библиотека / GCC / x86_64-RedHat-Linux / 4.6.2 /../../../../ включают в себя / C ++ / 4.6.2 / доб / ropeimpl.h: 433: 2: ошибка: использование необъявленный идентификатор "_Data_allocate" _Data_allocate (_S_ounded_up_size (__ old_len + __len));

A ошибка была подана против Clang для этого сообщения об ошибке, и разрешение было Clang является правильным, код библиотеки является недействительным.

Clang здесь правильный. В типе нет зависящих от типа аргументов позвонить _Data_allocate, поэтому поиск имени не выполняется во время определения шаблона.

Контекст для ошибочного кода:

  // Concatenate a C string onto a leaf rope by copying the rope data.
  // Used for short ropes.
  template <class _CharT, class _Alloc>
    typename rope<_CharT, _Alloc>::_RopeLeaf*
    rope<_CharT, _Alloc>::
    _S_leaf_concat_char_iter(_RopeLeaf* __r, const _CharT* __iter, size_t __len)
    {
      size_t __old_len = __r->_M_size;
      _CharT* __new_data = (_CharT*)
    _Data_allocate(_S_rounded_up_size(__old_len + __len));
      _RopeLeaf* __result;

      uninitialized_copy_n(__r->_M_data, __old_len, __new_data);
      uninitialized_copy_n(__iter, __len, __new_data + __old_len);
      _S_cond_store_eos(__new_data[__old_len + __len]);
      __try
    {
      __result = _S_new_RopeLeaf(__new_data, __old_len + __len,
                     __r->_M_get_allocator());
    }
      __catch(...)
    {
      _RopeRep::__STL_FREE_STRING(__new_data, __old_len + __len,
                      __r->_M_get_allocator());
      __throw_exception_again;
    }
      return __result;
    }

У меня вопрос: если этот код недействителен, есть ли простой обходной путь? G ++ компилирует это хорошо.

1 Ответ

4 голосов
/ 29 декабря 2011

При просмотре источника libstdc ++ выясняется, что определение функции-члена _Data_allocate является результатом расширения макроса __ROPE_DEFINE_ALLOCS в определении шаблона _Rope_base (обратите внимание, что создание экземпляра шаблона rope<_CharT, _Alloc> публично расширяет _Rope_base<_CharT, _Alloc>).

Вы можете попробовать квалифицировать звонок на _Data_allocate дальше. Вместо:

_Data_allocate(_S_rounded_up_size(__old_len + __len));

Попробуйте:

_Rope_base<_CharT, _Alloc>::_Data_allocate(_S_rounded_up_size(__old_len + __len));

Или просто:

_Base::_Data_allocate(_S_rounded_up_size(__old_len + __len));

из-за защищенного typedef _Rope_base<_CharT, _Alloc> _Base; в определении rope<_CharT, _Alloc>.

РЕДАКТИРОВАТЬ: У меня не установлен Clang локально, но я протестировал это с демонстрацией онлайн-компилятора Clang 3.0 .

Эта сильно урезанная версия не может быть скомпилирована с Clang 3.0 (ошибка: использование необъявленного идентификатора '_Data_allocate'):

#include <cstddef>
#include <memory>

template <typename _CharT, class _Alloc>
class _Rope_base : public _Alloc
{
public:
    typedef typename _Alloc::template rebind<_CharT>::other _DataAlloc;
    static _CharT * _Data_allocate(std::size_t __n) {
        return _DataAlloc().allocate(__n);
    }
};

template <typename _CharT, class _Alloc = std::allocator<_CharT> >
class rope : public _Rope_base<_CharT, _Alloc>
{
protected:
    typedef _Rope_base<_CharT, _Alloc> _Base;

public:
    rope()
    {
        _Data_allocate(0);
    }
};

int main()
{
    rope<char> r;
}

Уточняя вызов в _Data_allocate любым из предложенных выше способов, Clang 3.0 успешно компилирует его.

...