linux — В OS X простая программа на C ++ дает неверные результаты (которые являются результатом параметров командной строки «c ++ 03» против «c ++ 11»)

Эта простая программа (при компиляции в Linux) ПРАВИЛЬНО даст два разных ответа в зависимости от того, скомпилирована ли она с -std=c++0x или нет.

Проблема: я не могу воспроизвести то же самое на OS X (Mountain Lion, 10.8 SDK).
Что мне не хватает?

#include <iostream>
#include <sstream>

class Thing : public std::ostringstream
{
public:
Thing() : std::ostringstream() {}
virtual ~Thing() { std::cerr << str(); }
};

int main(int argc, const char * argv[]) {
Thing() << "Hello" << std::endl;
return 0;
}

Чтобы понять, что я имею в виду, сделайте следующее (сначала для Linux, просто чтобы посмотреть, как это должно работать):

> g++ main.cpp
> ./a.out
0x401471

> g++ -std=c++0x main.cpp
> ./a.out
Hello

Первый напечатает шестнадцатеричный адрес, второй напечатает «Привет». Это правильное поведение и потому, что оператор << разрешает две разные вещи (в C ++ 03 нет ссылок на rvalue, так что поехали).

Теперь попробуйте то же самое на OS X:


> xcrun c++ main.cpp
> ./a.out
0x10840dd88

(Это правильно производит шестнадцатеричный вывод.)


> xcrun c++ -std=c++0x main.cpp
> ./a.out
0x10840dd88

(Упс … все еще шестнадцатеричный вывод … Мы находимся в режиме C ++ 11x, но, возможно, правильные заголовки не используются?)


ПРИМЕЧАНИЕ: версия компилятора находится здесь:

> xcrun c++ --version
Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin12.2.0
Thread model: posix

ПРИМЕЧАНИЕ. Это не проблема C ++ как таковая, а проблема сборки OS X. Для тех, кто интересуется, причина того, что он дает разные результаты с C ++ 03 и C ++ 11, выделена ниже в одном из ответов.

8

Решение

Во-первых, ожидаемая разница в поведении заключается в том, что operator<<(std::ostream&, const char*) Перегрузка (на самом деле это специализация шаблона функции, но пока не имеет значения) имеет параметр типа std::ostream& и ссылка lvalue может связываться только с lvalue, и в вашем примере поток является rvalue, так что перегрузка не может быть использована. В C ++ 03 это означает, что единственная жизнеспособная перегрузка — это std::ostream::operator<<(const void*) функция-член, потому что функции-члены Можно вызываться для объектов rvalue, поэтому строка записывается в виде void* адрес в шестнадцатеричном формате. В C ++ 11 появился новый operator<<(std::ostream&&, const T&) шаблон функции, который позволяет записывать в rvalue потоки и пересылать operator<<(std::ostream&, const char*) перегрузка, поэтому строка выводится, а не шестнадцатеричный адрес.

В GNU / Linux вы, вероятно, используете довольно свежий выпуск GCC, который имеет довольно хорошую поддержку C ++ 11 как в компиляторе (g ++), так и в стандартной библиотеке (libstdc ++), поэтому он имеет operator<<(std::ostream&&, const T&) перегрузка и все просто работает.

В OS X вы, вероятно, используете Clang со стандартной библиотекой GCC, libstdc ++. Xcode поставляется с древней версией GCC по умолчанию (4.2), а стандартная библиотека из GCC 4.2 не поддерживает C ++ 11, поэтому не имеет operator<< перегрузка для rvalue потоков. С помощью -std=c++0x говорит Clang о поддержке функций языка C ++ 11 (таких как ссылки на rvalue), но волшебным образом не заставляет библиотеку GCC 4.2 расширять код C ++ 11, который даже в мгновение ока не представлялся стандартному комитету, когда GCC 4.2 был вышел. Вместо того, чтобы поставлять неисторический libstdc ++, Apple вместо этого написала собственную реализацию стандартной библиотеки для проектов LLVM и Clang. С помощью -stdlib=libc++ говорит clang использовать реализацию стандартной библиотеки libc ++ вместо древнего libstdc ++. Поскольку libc ++ была написана недавно, она имеет operator<< перегрузка для ссылок rvalue.

17

Другие решения

Похоже, что проблема с clang, использующим libstdc ++ по умолчанию, а не libc ++. Компилируем так: clang++ -std=c++0x -stdlib=libc++ test.cpp приводит к ожидаемому результату.

6

По вопросам рекламы [email protected]