Информация об изменениях

Сообщение Re: Чудны способности твои, о стандарт ! от 02.10.2015 11:11

Изменено 02.10.2015 11:14 wander

Опечатки

Здравствуйте, B0FEE664, Вы писали:

BFE>Может уже появился какой способ собрать указатели на локальные строки в глобальных переменных ? (Например, шаблон параметризованный локальной строкой...)


Это и в С++11 можно было сделать.
Вот ты там писал, что это можно использоватья для перевода приложения.
Понравилась твоя идея, вот мой концепт реализации (работает в GCC и СLang c С++11).
В принципе даже контейнеры не понадобились.
Вспомогательная кухня, применил тут кое-какие свои давние идеи по реализации настоящих ct-строк:
  ct_string.h
#ifndef CT_STRING_H_INCLUDED
#define CT_STRING_H_INCLUDED

namespace ct
{

template <char ...Chars>
struct string
{
    enum { length = sizeof...(Chars) - 1 };

    static char const value[];
};

template <char ...Chars>
char const string<Chars...>::value[] = { Chars... };

} // ct

#endif // CT_STRING_H_INCLUDED

  ct_indices_utils.h
#ifndef CT_INDICES_UTILS_H_INCLUDED
#define CT_INDICES_UTILS_H_INCLUDED

#include <cstddef>

namespace ct
{

template <size_t ...I>
struct indices
{ };

template <size_t Max, size_t ...Indices>
struct make_indices
    : make_indices<Max - 1, Max - 1, Indices...>
{ };

template <size_t ...Indices>
struct make_indices<0, Indices...>
    : indices<Indices...>
{
    using type = indices<Indices...>;
};

} // ct

#endif // CT_INDICES_UTILS_H_INCLUDED

  ct_string_utils.h
#ifndef CT_STRING_UTILS_H_INCLUDED
#define CT_STRING_UTILS_H_INCLUDED

#include "ct_string.h"
#include "ct_indices_utils.h"

namespace ct
{

template <typename Str, typename I>
struct string_gen;

template <typename Str, size_t ...I>
struct string_gen<Str, ::ct::indices<I...>>
    : ::ct::string<Str{}.chars[I]...>
{ };

template <typename Str, size_t Len>
struct make_string
    : string_gen<Str, typename ::ct::make_indices<Len>::type>
{ };

} // ct

#endif // CT_STRING_UTILS_H_INCLUDED

Сам транслятор, довольно примитивный.
  translator.h
#ifndef TRANSLATOR_H_INCLUDED
#define TRANSLATOR_H_INCLUDED

#include "ct_string.h"
#include "ct_indices_utils.h"
#include "ct_string_utils.h"

class Translator
{
public:
    enum { LangMax = 5 };

    struct Holder
    {
        char const * m_strings[LangMax];
    };

private:
    template <typename Value>
    struct Storage : Value, Holder
    {
        template <size_t ...I>
        Storage(Translator & self, ct::indices<I...>)
            : Holder{ { ((void)I, Value::value)... } }
        { }

        explicit Storage(Translator & self)
            : Storage(self, ct::make_indices<LangMax> {})
        { }
    };

    template <char ...Chars>
    Holder * addString(ct::string<Chars...> const &)
    {
        static Storage<ct::string<Chars...>> s(*this);
        return &s;
    }

public:
    static Translator & instance()
    {
        static Translator inst;
        return inst;
    }

    template <typename Original, typename Translated>
    void addTranslation(size_t lang)
    {
        Holder * h = this->addString(Original{});
        h->m_strings[lang] = Translated::value;
    }
    template <typename Original>
    char const * addString()
    {
        Holder * h = this->addString(Original{});
        return h->m_strings[m_lang];
    }

    static void setLang(size_t lang)
    {
        instance().m_lang = lang;
    }

private:
    size_t m_lang = 0;
};

#define TR(str) []()     {                                                                           struct StringType1 { const char * chars = (str); };                     using type1 = ::ct::make_string<StringType1, sizeof((str))>;            return Translator::instance().addString<type1>();                   }()

#define SETUP_TR(lang, orig, trans) []()     {                                                                           struct StringType1 { const char * chars = (orig);  };                   using type1 = ::ct::make_string<StringType1, sizeof((orig))>;           struct StringType2 { const char * chars = (trans); };                   using type2 = ::ct::make_string<StringType2, sizeof((trans))>;          Translator::instance().addTranslation<type1, type2>(lang);              return true;                                                        }()

#endif // TRANSLATOR_H_INCLUDED

Использование:
#include <cstdio>

#include "translator.h"

enum { RUS = 1 };

namespace {
bool f1 = SETUP_TR(RUS, "start", "старт");
bool f2 = SETUP_TR(RUS, "text", "текст");
}

int main()
{
    Translator::setLang(RUS);

    printf("%s\n", TR("start"));
    printf("%s\n", TR("start"));
    printf("%s\n", TR("text"));
}

SETUP_TR могут находиться в любом файле. Допустим, можно завести russian_tr.cpp и там написать перевод для нужных строк.
В продвинутой реализации можно было бы уйти от голых указателей и сделать свой класс "переводной" строки.
Тест "одним файлом" в онлайн компиляторе: http://rextester.com/WYUMS67445
Может быть будет полезно.
Re: Чудны способности твои, о стандарт !
Здравствуйте, B0FEE664, Вы писали:

BFE>Может уже появился какой способ собрать указатели на локальные строки в глобальных переменных ? (Например, шаблон параметризованный локальной строкой...)


Это и в С++11 можно было сделать.
Вот ты там писал, что это можно использовать для перевода приложения.
Понравилась твоя идея, вот мой концепт реализации (работает в GCC и СLang c С++11).
В принципе даже контейнеры не понадобились.
Вспомогательная кухня, применил тут кое-какие свои давние идеи по реализации настоящих ct-строк:
  ct_string.h
#ifndef CT_STRING_H_INCLUDED
#define CT_STRING_H_INCLUDED

namespace ct
{

template <char ...Chars>
struct string
{
    enum { length = sizeof...(Chars) - 1 };

    static char const value[];
};

template <char ...Chars>
char const string<Chars...>::value[] = { Chars... };

} // ct

#endif // CT_STRING_H_INCLUDED

  ct_indices_utils.h
#ifndef CT_INDICES_UTILS_H_INCLUDED
#define CT_INDICES_UTILS_H_INCLUDED

#include <cstddef>

namespace ct
{

template <size_t ...I>
struct indices
{ };

template <size_t Max, size_t ...Indices>
struct make_indices
    : make_indices<Max - 1, Max - 1, Indices...>
{ };

template <size_t ...Indices>
struct make_indices<0, Indices...>
    : indices<Indices...>
{
    using type = indices<Indices...>;
};

} // ct

#endif // CT_INDICES_UTILS_H_INCLUDED

  ct_string_utils.h
#ifndef CT_STRING_UTILS_H_INCLUDED
#define CT_STRING_UTILS_H_INCLUDED

#include "ct_string.h"
#include "ct_indices_utils.h"

namespace ct
{

template <typename Str, typename I>
struct string_gen;

template <typename Str, size_t ...I>
struct string_gen<Str, ::ct::indices<I...>>
    : ::ct::string<Str{}.chars[I]...>
{ };

template <typename Str, size_t Len>
struct make_string
    : string_gen<Str, typename ::ct::make_indices<Len>::type>
{ };

} // ct

#endif // CT_STRING_UTILS_H_INCLUDED

Сам транслятор, довольно примитивный.
  translator.h
#ifndef TRANSLATOR_H_INCLUDED
#define TRANSLATOR_H_INCLUDED

#include "ct_string.h"
#include "ct_indices_utils.h"
#include "ct_string_utils.h"

class Translator
{
public:
    enum { LangMax = 5 };

    struct Holder
    {
        char const * m_strings[LangMax];
    };

private:
    template <typename Value>
    struct Storage : Value, Holder
    {
        template <size_t ...I>
        Storage(Translator & self, ct::indices<I...>)
            : Holder{ { ((void)I, Value::value)... } }
        { }

        explicit Storage(Translator & self)
            : Storage(self, ct::make_indices<LangMax> {})
        { }
    };

    template <char ...Chars>
    Holder * addString(ct::string<Chars...> const &)
    {
        static Storage<ct::string<Chars...>> s(*this);
        return &s;
    }

public:
    static Translator & instance()
    {
        static Translator inst;
        return inst;
    }

    template <typename Original, typename Translated>
    void addTranslation(size_t lang)
    {
        Holder * h = this->addString(Original{});
        h->m_strings[lang] = Translated::value;
    }
    template <typename Original>
    char const * addString()
    {
        Holder * h = this->addString(Original{});
        return h->m_strings[m_lang];
    }

    static void setLang(size_t lang)
    {
        instance().m_lang = lang;
    }

private:
    size_t m_lang = 0;
};

#define TR(str) []() \
    {                                                                   \
        struct StringType1 { const char * chars = (str); };             \
        using type1 = ::ct::make_string<StringType1, sizeof((str))>;    \
        return Translator::instance().addString<type1>();               \
    }()

#define SETUP_TR(lang, orig, trans) []() \
    {                                                                   \
        struct StringType1 { const char * chars = (orig);  };           \
        using type1 = ::ct::make_string<StringType1, sizeof((orig))>;   \
        struct StringType2 { const char * chars = (trans); };           \
        using type2 = ::ct::make_string<StringType2, sizeof((trans))>;  \
        Translator::instance().addTranslation<type1, type2>(lang);      \
        return true;                                                    \
    }()

#endif // TRANSLATOR_H_INCLUDED

Использование:
#include <cstdio>

#include "translator.h"

enum { RUS = 1 };

namespace {
bool f1 = SETUP_TR(RUS, "start", "старт");
bool f2 = SETUP_TR(RUS, "text", "текст");
}

int main()
{
    Translator::setLang(RUS);

    printf("%s\n", TR("start"));
    printf("%s\n", TR("start"));
    printf("%s\n", TR("text"));
}

SETUP_TR могут находиться в любом файле. Допустим, можно завести russian_tr.cpp и там написать перевод для нужных строк.
В продвинутой реализации можно было бы уйти от голых указателей и сделать свой класс "переводной" строки.
Тест "одним файлом" в онлайн компиляторе: http://rextester.com/WYUMS67445
Может быть будет полезно.