Уровне исходного кода портативный с++ литералы Юникод


Консоль Windows Windows делают, к сожалению, не поддерживает поток ввода/вывода международных символов. Например, в Windows 7, вы все еще можете сделать "chcp 65001" (устанавливает активную кодовую страницу в UTF-8), тип "больше", и получаете аварии.

Это означает, что для начинающего писать "Привет, Мир!" программа, которая практически невозможно:

  • и национальных символов в литералах
  • даст те же результаты в *Nix и Windows, независимо от страны

После небольшой дискуссии по этому поводу на заряд рассылки я присел к более полному осуществлению идеи, которые я набросал здесь, а именно использовать натуральное кодирование операционной системы за внутренние струны, которые на практике это означает, что UTF-8 для внутренних строк на *Nix и UTF-16 для внутренних строки в Windows. Стоит отметить, что, например, в библиотеке ICU, по крайней мере, согласно его документации, использует кодировке UTF-16 строк.

С UTF-8 в качестве общего внешнего кодирования, имеет:

    Extern        Intern        E.g. ICU library
    UTF-8    -    UTF-8   <->   UTF-16                  <- for *nix
    UTF-8   <->   UTF-16   -    UTF-16                  <- for Windows

В поддержку того, что я определяю макрос с невероятно короткого имени У, который адаптирует литерал на платформу один компилирует и создает строго типизированный строку или символ. Типирование помогает избежать использование функций в режиме нон-портативный манера. И это позволяет зависимый аргумент поиска, как это:

#include <progrock/cppx/u/adapted_iostream.h>
using namespace std;
namespace u = progrock::cppx::u;

int main()
{
    u::out << U( "Hello, world!" ) << endl;
    u::out << U( "2+2 = " ) << 2 + 2 << endl;
    u::out << U( "Blåbærsyltetøy! 日本国 кошка!" ) << endl;
}

Здесь у::вне либо с std::соиь (для *Nix) или с std::wcout (для Windows). И исходный код должен быть сохранен как UTF-8 с BOM для того, чтобы красиво составить с г++ и Visual С++.

Если стандартный вывод идет в окно консоли Windows, затем норвежские, российские и китайские иероглифы результат в правильных кодовых точек Unicode в буфере текст в окно консоли. Норвежский и русский отображается нормально, китайской отображаются в виде прямоугольников (на моей машине), и текст может быть скопирован правильно, например блокнот, который может отображать все это. Если стандартный вывод перенаправляется или на свирели, то результатом является UTF-8.

Это в основном Программирование хобби, и только с компиляторами у меня есть на моей машине, а именно Visual С++ и G++. Я надеюсь, что некоторые люди не только понял вопрос, но могут дать полезную обратную связь.

progrock/cppx/у/adapted_iostream.ч

#pragma once
// Copyright (c) 2011, Alf P. Steinbach


//--------------------------------------------------------- Dependencies:

#include <progrock/cppx/u/translating_streams.compiler_dependent.h> // translating?Stream
#include <progrock/cppx/u/cpp_string_output.os_dependent.h>         // writeTo
#include <progrock/cppx/u.h>                                        // Encoding::Enum etc.

#include <iostream>
#include <locale>
//#include <codecvt>          // C++11 std::codecvt_utf8_utf16, not supported by g++ 4.4.1.
#include <progrock/cppx/u/CodecUtf8.h>      // Sort of equivalent DIY functionality instead.


//--------------------------------------------------------- Implementation:

namespace progrock{ namespace cppx{ namespace u {

    namespace naturalEncoding {
        namespace detail {
            template< Encoding::Enum encoding >
            struct StdStreamsBase
            {
                typedef EncodingTraits< encoding >      Traits;

                typedef std::basic_istream< typename Traits::Raw::Value >   IStream;
                typedef std::basic_ostream< typename Traits::Raw::Value >   OStream;
            };
        };  // namespace detail

        template< Encoding::Enum encoding >
        struct StdStreams;

        template<>
        struct StdStreams< Encoding::utf8 >
            : detail::StdStreamsBase< Encoding::utf8 >
        {
            static IStream& inStream()      { return std::cin; }
            static OStream& outStream()     { return std::cout; }
            static OStream& errStream()     { return std::cerr; }
            static OStream& logStream()     { return std::clog; }
        };

        template<>
        struct StdStreams< Encoding::utf16 >
            : detail::StdStreamsBase< Encoding::utf16 >
        {
        private:
            template< class Stream >
            static Stream& withUtf8Conversion( Stream& stream )
            {
                std::locale const  utf8Locale( stream.getloc(), new CodecUtf8() );
                stream.imbue( utf8Locale );
                return stream;
            }

        public:
            static IStream& inStream()
            {
                static IStream& stream = withUtf8Conversion( translatingInWStream() );
                return stream;
            }

            static OStream& outStream()
            {
                static OStream& stream = withUtf8Conversion( translatingOutWStream() );
                return stream;
            }

            static OStream& errStream()
            {
                static OStream& stream = withUtf8Conversion( translatingErrWStream() );
                return stream;
            }

            static OStream& logStream()
            {
                static OStream& stream = withUtf8Conversion( translatingLogWStream() );
                return stream;
            }
        };
    }  // namespace naturalEncoding

    typedef naturalEncoding::StdStreams< u::encoding >::IStream     IStream;
    typedef naturalEncoding::StdStreams< u::encoding >::OStream     OStream;

    static IStream& in      = naturalEncoding::StdStreams< encoding >::inStream();
    static OStream& out     = naturalEncoding::StdStreams< encoding >::outStream();
    static OStream& err     = naturalEncoding::StdStreams< encoding >::errStream();
    static OStream& log     = naturalEncoding::StdStreams< encoding >::logStream();

    inline bool isCommon( OStream const& stream )
    {
        OStream const* const p = &stream;
        return (p == &out || p == &err || p == &log);
    }

    inline OStream& operator<<( OStream& stream, CodingValue const v )
    {
        if( isCommon( stream ) )            // <-- Is just an optimization.
        {
            return writeTo( stream, v );    // Special-cases Windows console output.
        }
        else
        {
            return stream << raw( v );
        }
    }

    inline OStream& operator<<( OStream& stream, CodingValue const s[] )
    {
        if( isCommon( stream ) )            // <-- Is just an optimization.
        {
            return writeTo( stream, s );    // Special-cases Windows console output.
        }
        else
        {
            return stream << raw( s );
        }
    }
} } }  // namespace progrock::cppx::u

Как я скопировал его для публикации здесь, я добавил пару рядный , что я забыл. Это очень краткая характеристика работы. Он работает на выход (я не проверял с++ библиотеки iostream материалов), но, возможно, очень далека от совершенства кода!

progrock\cppx\у.ч

#pragma once
// Copyright (c) 2011, Alf P. Steinbach


//--------------------------------------------------------- Dependencies:

#include <progrock/cppx/u_encoding_choice.os_dependent.h>   // CPPX_NATURAL_ENCODING
#include <progrock/cppx/c++11_emulation.h>                  // CPPX_STATIC_ASSERT, CPPX_NOEXCEPT
#include <progrock/cppx/stdlib_typedefs.h>                  // cppx::Size

#include <locale>       // std::char_traits
#include <utility>      // comparison operators


//--------------------------------------------------------- Interface:

#if     CPPX_NATURAL_ENCODING == CPPX_ENCODING_UTF16
#
    CPPX_STATIC_ASSERT( sizeof( wchar_t ) == 2 );
#   define CPPX_U_ENCODING ::progrock::cppx::u::Encoding::utf16
#   define U( aLiteral ) ::progrock::cppx::u::typed( L##aLiteral )
#
#elif   CPPX_NATURAL_ENCODING == CPPX_ENCODING_UTF8
#
#   define CPPX_U_ENCODING ::progrock::cppx::u::Encoding::utf8
#   define U( aLiteral ) ::progrock::cppx::u::typed( aLiteral )
#
#else
#   error "The natural encoding for this OS is not supported, sorry."
#endif

namespace progrock { namespace cppx { namespace u {
    using namespace std::rel_ops;       // operator!= etc.

    struct Encoding { enum Enum{ ansi, utf8, utf16 }; };

    template< Encoding::Enum a > struct EncodingUnit;
    template<> struct EncodingUnit< Encoding::ansi > { typedef char Type; };
    template<> struct EncodingUnit< Encoding::utf8 > { typedef char Type; };
    template<> struct EncodingUnit< Encoding::utf16 > { typedef wchar_t Type; };

    template< Encoding::Enum e >
    struct EncodingTraits;              // Must be specialized due to Visual C++ bug.

    template<>
    struct EncodingTraits< Encoding::utf8 >
    {
            typedef char                            UnitType;
            typedef std::char_traits< UnitType >    UnitTraits;

            struct Raw
            {
                typedef UnitType                    Value;
                typedef UnitTraits::int_type        ExtendedValue;
            };

            enum Value              : Raw::Value {};
            enum ExtendedValue      : Raw::ExtendedValue {};

            CPPX_STATIC_ASSERT( sizeof( Value ) == sizeof( Raw::Value ) );
            CPPX_STATIC_ASSERT( sizeof( ExtendedValue ) == sizeof( Raw::ExtendedValue ) );
    };

    template<>
    struct EncodingTraits< Encoding::utf16 >
    {
            typedef wchar_t                         UnitType;
            typedef std::char_traits< UnitType >    UnitTraits;

            struct Raw
            {
                typedef UnitType                    Value;
                typedef UnitTraits::int_type        ExtendedValue;
            };

            enum Value              : Raw::Value {};
            enum ExtendedValue      : Raw::ExtendedValue {};

            CPPX_STATIC_ASSERT( sizeof( Value ) == sizeof( Raw::Value ) );
            CPPX_STATIC_ASSERT( sizeof( ExtendedValue ) == sizeof( Raw::ExtendedValue ) );
    };

    Encoding::Enum const    encoding    = CPPX_U_ENCODING;

    typedef EncodingTraits< encoding >      Traits;
    typedef Traits::Value                   CodingValue;
    typedef Traits::ExtendedValue           ExtendedCodingValue;
    typedef Traits::Raw::Value              RawCodingValue;
    typedef Traits::Raw::ExtendedValue      RawExtendedCodingValue;

    inline RawCodingValue raw( CodingValue const v ) CPPX_NOEXCEPT
    {
        return v;
    }

    inline RawCodingValue* raw( CodingValue* p ) CPPX_NOEXCEPT
    {
        return reinterpret_cast< RawCodingValue* >( p );
    }

    inline RawCodingValue const* raw( CodingValue const* p ) CPPX_NOEXCEPT
    {
        return reinterpret_cast< RawCodingValue const* >( p );
    }

    template< Size size >
    inline RawCodingValue (&raw( CodingValue (&s)[size] )) [size]
    {
        return reinterpret_cast< RawCodingValue (&)[size] >( s );
    }

    template< Size size >
    inline RawCodingValue const (&raw( CodingValue const (&s)[size] ) CPPX_NOEXCEPT)[size]
    {
        return reinterpret_cast< RawCodingValue const (&)[size] >( s );
    }

    enum Koenig {};

    inline CodingValue typed( RawCodingValue const v ) CPPX_NOEXCEPT
    {
        return CodingValue( v );
    }

    inline CodingValue typed( Koenig, RawCodingValue const v ) CPPX_NOEXCEPT
    {
        return CodingValue( v );
    }

    inline CodingValue* typed( RawCodingValue* const p ) CPPX_NOEXCEPT
    {
        return reinterpret_cast< CodingValue* >( p );
    }

    inline CodingValue* typed( Koenig, RawCodingValue* const p ) CPPX_NOEXCEPT
    {
        return reinterpret_cast< CodingValue* >( p );
    }

    inline CodingValue const* typed( RawCodingValue const* const p ) CPPX_NOEXCEPT
    {
        return reinterpret_cast< CodingValue const* >( p );
    }

    inline CodingValue const* typed( Koenig, RawCodingValue const* const p ) CPPX_NOEXCEPT
    {
        return reinterpret_cast< CodingValue const* >( p );
    }

    template< Size size >
    inline CodingValue (&typed( RawCodingValue (&s)[size] ) CPPX_NOEXCEPT)[size]
    {
        return reinterpret_cast< CodingValue (&)[size] >( s );
    }

    template< Size size >
    inline CodingValue (&typed( Koenig, RawCodingValue (&s)[size] ) CPPX_NOEXCEPT)[size]
    {
        return reinterpret_cast< CodingValue (&)[size] >( s );
    }

    template< Size size >
    inline CodingValue const (&typed( RawCodingValue const (&s)[size] ) CPPX_NOEXCEPT)[size]
    {
        return reinterpret_cast< CodingValue const (&)[size] >( s );
    }

    template< Size size >
    inline CodingValue const (&typed( Koenig, RawCodingValue const (&s)[size] ) CPPX_NOEXCEPT)[size]
    {
        return reinterpret_cast< CodingValue const (&)[size] >( s );
    }

} } }  // namespace progrock::cppx::u

namespace std {

    // Requirements specified by C++11 §21.2.1/1 table 62.
    template<>
    class char_traits< ::progrock::cppx::u::CodingValue >
    {
    private:
        typedef ::progrock::cppx::u::Koenig     adl;

    public:
        typedef ::progrock::cppx::u::CodingValue            char_type;
        typedef ::progrock::cppx::u::ExtendedCodingValue    int_type;

        typedef ::progrock::cppx::u::Traits::UnitTraits     Std;

        typedef Std::off_type                  off_type;
        typedef Std::pos_type                  pos_type;
        typedef Std::state_type                state_type;

        static bool eq( char_type a, char_type b ) CPPX_NOEXCEPT
        { return (a == b); }

        static bool lt( char_type a, char_type b ) CPPX_NOEXCEPT
        { return (a < b); }

        static int compare( char_type const* s1, char_type const* s2, size_t n )
        { return Std::compare( raw( s1 ), raw( s2 ), n ); }

        static size_t length( char_type const* s )
        { return Std::length( raw( s ) ); }

        static char_type const* find( char_type const* s, size_t n, char_type const a )
        { return typed( adl(), Std::find( raw( s ), n, raw( a ) ) ); }

        static char_type* move( char_type* s1, char_type const* s2, size_t n )
        { return typed( adl(), Std::move( raw( s1 ), raw( s2 ), n ) ); }

        static char_type* copy( char_type* s1, char_type const* s2, size_t n )
        { return typed( adl(), Std::copy( raw( s1 ), raw( s2 ), n ) ); }

        static void assign( char_type& c1, char_type const c2 ) CPPX_NOEXCEPT
        { c1 = c2; }

        static char_type* assign( char_type* s, size_t n, char_type const a )
        { return typed( adl(), Std::assign( raw( s ), n, raw( a ) ) ); }

        static int_type not_eof( int_type const c ) CPPX_NOEXCEPT
        { return int_type( Std::not_eof( c ) ); }

        static char_type to_char_type( int_type const c ) CPPX_NOEXCEPT
        { return typed( c ); }

        static int_type to_int_type( char_type const c ) CPPX_NOEXCEPT
        { return int_type( c ); }

        static bool eq_int_type( int_type const c1, int_type const c2 ) CPPX_NOEXCEPT
        { return (c1 == c2); }

        static int_type eof() CPPX_NOEXCEPT
        { return int_type( Std::eof() ); }
    };

}  // namespace std


364
8
задан 8 ноября 2011 в 01:11 Источник Поделиться
Комментарии
1 ответ

Поскольку код должен работать для Unix ПРАГМА-это плохая идея.

#pragma once

Предпочитают использовать обычный включают в себя охранников.

Вы здесь наполняя ручьи:

            std::locale const  utf8Locale( stream.getloc(), new CodecUtf8() );
stream.imbue( utf8Locale );
return stream;

Единственная проблема я вижу в том, что после того, как вы начали использовать поток на любые попытки наполнить может быть прекращена (или она используется слишком они зафиксировали, что в C++11).

Теперь я предполагаю, что вы пытаетесь заставить это инициализации перед использованием с:

static IStream& in      = naturalEncoding::StdStreams< encoding >::inStream();
static OStream& out = naturalEncoding::StdStreams< encoding >::outStream();
static OStream& err = naturalEncoding::StdStreams< encoding >::errStream();
static OStream& log = naturalEncoding::StdStreams< encoding >::logStream();

Это будет работать 99% времени, но если кто-то начинает запись (используя один из СТД:: потоки (вход/выход/ошибка/журнала) в конструкторе глобального масштаба статическое время жизни объекта, то все ставки выключены). Поскольку это редкий случай, я не слишком волновался, но вы должны документировать это где-нибудь в верхней части заголовка файла (при условии, что это проблема).

Я не вижу определения у() или написать() или сырых() или CodingValue

4
ответ дан 8 ноября 2011 в 03:11 Источник Поделиться