полная специализация std :: basic_string (конфликт g ++) - PullRequest
4 голосов
/ 24 апреля 2010

Я пытаюсь определить полную специализацию std::basic_string< char, char_traits<char>, allocator<char> >, которая является typedef'd (в g ++) заголовком <string>.

Проблема в том, что если я сначала включу <string>, g ++ видит typedef как экземпляр basic_string и выдает мне ошибки. Если я сначала делаю свою специализацию, то у меня нет проблем.

Я смогу определить свою специализацию после включения <string>. Что мне нужно сделать, чтобы это сделать?

Мой код:

#include <bits/localefwd.h>

//#include <string> // <- uncommenting this line causes compilation to fail

namespace std {
template<>
class basic_string< char, char_traits<char>, allocator<char> >
{
public:
    int blah() { return 42; }
    size_t size() { return 0; }
    const char *c_str() { return ""; }
    void reserve(int) {}
    void clear() {}
};
}

#include <string>
#include <iostream>

int main() {
    std::cout << std::string().blah() << std::endl;
}

Приведенный выше код работает нормально. Но, если я раскомментирую первую строку #include <string>, я получу следующие ошибки компилятора:

blah.cpp:7: error: specialization of ‘std::basic_string<char, std::char_traits<char>, std::allocator<char> >’ after instantiation
blah.cpp:7: error: redefinition of ‘class std::basic_string<char, std::char_traits<char>, std::allocator<char> >’
/usr/include/c++/4.4/bits/stringfwd.h:52: error: previous definition of ‘class std::basic_string<char, std::char_traits<char>, std::allocator<char> >’
blah.cpp: In function ‘int main()’:
blah.cpp:22: error: ‘class std::string’ has no member named ‘blah’

Строка 52 из /usr/include/c++/4.4/bits/stringfwd.h:

  template<typename _CharT, typename _Traits = char_traits<_CharT>,
           typename _Alloc = allocator<_CharT> >
    class basic_string;

Насколько я знаю, это всего лишь прямая делкарация шаблона, а не экземпляр, как утверждает g ++.

Строка 56 из /usr/include/c++/4.4/bits/stringfwd.h:

   typedef basic_string<char>    string;

Насколько я знаю, это просто typedef, а не экземпляр.

Так почему эти строки конфликтуют с моим кодом? Что я могу сделать, чтобы это исправить, кроме того, что мой код всегда включен до <string>?

Ответы [ 2 ]

10 голосов
/ 24 апреля 2010

Вам разрешено специализировать стандартную библиотеку только в том случае, если специализация зависит от определенного пользователем имени с внешней связью. char не соответствует этому требованию, и вы получаете неопределенное поведение.

Это указано в 17.4.3.1 [lib.reserver.names] /1.

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

14.7.3 [temp.expl.spec] / 6

0 голосов
/ 24 апреля 2010

Как правило, вы не должны определять или специализировать что-либо, кроме класса признаков, в пространстве имен std, и вам, конечно, не следует пытаться изменить определение типа подчиненного типа std :: string.

Вместо того, чтобы специализировать basic_string, вы должны создать свой собственный тип данных персонажа в своем собственном пространстве имен, затем вы должны специализировать std :: char_traits для этого типа (но ничего больше в пространстве имен std), а затем вы должны сделать удобный typedef для basic_string создается с этими типами в вашем собственном пространстве имен (не в пространстве имен std, которое принадлежит стандарту C ++ и не должно изменяться пользователями).

...