Форум программистов, компьютерный форум CyberForum.ru

Создать список ф-ций определяемых в файле (а-ля initializer list) в compile time - C++

Войти
Регистрация
Восстановить пароль
Другие темы раздела
C++ Контроль звуковых потоков http://www.cyberforum.ru/cpp/thread1626276.html
Всем привет,не знал,где разместить тему,т.к вроде тема не для новичков,но на эксперта не тянет. Проблема следующая,необходимо получить доступ к различным потокам выхода с возможностью их редактирования. Под выходными потоками я имею ввиду все те варианты взаимодействия компьютера с внешним миром(выхдной звуковой поток,http запросы от браузера,поток картинки на главном и побочных экранах)
C++ Электронная сваха: составить счастливый набор пар 2 задание: «Электронная сваха». Имеется N мужчин и N женщин. Имеются также данные о предпочтениях каждого мужчины по отношению к каждой женщине. Аналогичные данные имеются и для женщин. Требуется составить такой набор пар, чтобы общество, получившееся из таких семей, было максимально счастливым помогите решить, я не знаю как...я опустил руки( http://www.cyberforum.ru/cpp/thread1625591.html
C++ Linux Bash: ./main.o: Отказано в доступе
Установил библиотеку sfml через apt-get, вставил тестовый код, в терминале прописал путь, далее g++ -c main.cpp, скомпилировалось, пишу ./main.o выкидывает ошибку: bash: ./main.o: Отказано в доступе. Даже под рутом не работает.
C++ Перезаписывать index.html каждый раз, когда меняется количество файлов в директории
нужно сделать так, чтобы каждый раз когда меняется количество файлов в каталоге C:\\, программа перезаписывала файл index.html #include <stdio.h> #include <iostream> #include <windows.h> #include <fstream> using namespace std; int main() {
C++ Сделать валидатор http://www.cyberforum.ru/cpp/thread1622460.html
Здравствуйте, уважаемые) На форуме только поселился, если кто-то может помочь, то буду очень благодарен) К сожалению, я не очень силен(надеюсь, что пока), в регулярных выражениях, да и с qt мало поработал, вопрос может показаться глупым, но ближе к делу) Задача: написать валидатор, вводить можно строку - стока с указанием единиц измерения, к примеру 25645км_35м, где "_" - это пробел. Все это...
 

Показать сообщение отдельно
DrOffset
6851 / 4062 / 927
Регистрация: 30.01.2014
Сообщений: 6,859
31.12.2015, 01:23     Создать список ф-ций определяемых в файле (а-ля initializer list) в compile time
Цитата Сообщение от ForEveR Посмотреть сообщение
было бы очень интересно увидеть.
Публиковал относительно недавно на другом российском форуме. Вариация на тему compile-time механизма перевода приложения.
С++11 (в С++14 будет чуть поменьше кода)
ct_string.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#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
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#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

Использование:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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);
 
    std::printf("%s\n", TR("start"));
    std::printf("%s\n", TR("start"));
    std::printf("%s\n", TR("text"));
}
http://rextester.com/WYUMS67445

Добавлено через 11 часов 16 минут
Kastaneda, в общем выдалась свободная минутка, и я слегка улучшил первоначальный код и избавился от некоторых проблем.
Нужен C++14, но можно и без него, просто мне уже не очень охота переделывать.
Итак, сперва чего удалось достичь:
1) Теперь нет глобальных переменных-указателей, вместо этого полноценные функции (хоть и шаблонные).
2) Вследствие этого теперь возможно поместить реализацию функций в заголовочный файл. Хитрость с явным инстанцированием частичной специализации, вместо применения полной специализации позволит избежать multiple definition.
3) Избавился от вектора в качестве хранилища. Теперь там связный список на статических объектах. Куча не используется до входа в main вообще.
4) Идентификация файла через compile-time строковый тег - коллизиям говорим "нет" . Кстати, проблемы одинаковых файлов не возникнет, по крайней мере на GCC и Clang, т.к. __FILE__ там включает полное имя, а не короткое.
5) В качестве регистрируемой функции можно использовать функцию с любой(!) сигнатурой. Будет создано по отдельному хранилищу на каждый тип. Предусмотрена возможность задать нужный тип для группового вызова.

Минусы конечно тоже есть. Из основных:
- Перегрузка не поддерживается.
- Страшный синтаксис.
- Время компиляции растет.
- Функции для прямого вызова - шаблонные. Отсюда проблемы с взятием адреса такой функции, приходится указывать аргументы шаблона ну и т.п.

ct_string_v1.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#ifndef CT_STRING_V1_H_INCLUDED
#define CT_STRING_V1_H_INCLUDED
 
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/config/limits.hpp>
 
template <char ...Chars>
struct string
{};
 
namespace detail
{
    template <typename Res, char ...Chars>
    struct trim_zeros_impl;
 
    template <char... N, char C, char ...Chars>
    struct trim_zeros_impl<string<N...>, C, Chars...>
        : std::conditional<C
            , trim_zeros_impl<string<N..., C>, Chars...>
            , trim_zeros_impl<string<N..., 0>> // force recursion end
          >::type
    { };
 
    template <char ...Chars>
    struct trim_zeros_impl<string<Chars...>>
    {
        using type = string<Chars...>;
    };
}
template <char ...Chars>
struct trim_zeros
    : detail::trim_zeros_impl<string<>, Chars...>
{ };
 
#define STRING_TO_CHARS_BY_ONE(Z, N, STR) \
        BOOST_PP_COMMA_IF(N) N >= sizeof(STR) ? '\0' : STR[N]
 
#define STRING_TO_CHARS(LEN, STR)  \
        BOOST_PP_REPEAT(LEN, STRING_TO_CHARS_BY_ONE, STR)
 
#define MAKE_CT_STRING(STR) trim_zeros<STRING_TO_CHARS(256, STR)>::type
 
#endif // CT_STRING_V1_H_INCLUDED

func_registry.h

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#ifndef FUNC_REGISTRY_H_INCLUDED
#define FUNC_REGISTRY_H_INCLUDED
 
#include <type_traits>
#include <utility>
 
#include <vector>
#include <cstddef>
 
#include "ct_string_v1.h"
/*----------------------------------------------------------------------------*/
template <typename File, typename FType>
struct FunctionReg
{
    explicit FunctionReg(FType f);
 
    FunctionReg * next;
    FType *       call;
};
/*----------------------------------------------------------------------------*/
template <typename File, typename F>
class FunctionStorage;
 
template <typename File, typename Ret, typename ...Args>
class FunctionStorage<File, Ret(Args...)>
{
    using FuncPtrType  = Ret(*)(Args...);
    using FuncRegistry = FunctionReg<File, Ret(Args...)>;
 
    FunctionStorage()
        : m_first(), m_last(), m_len()
    {}
public:
    static FunctionStorage & instance()
    {
        static FunctionStorage inst;
        return inst;
    }
    void append(FuncRegistry * reg)
    {
        if(m_first)
        {
            m_last->next = reg;
        }
        else
        {
            m_first = reg;
        }
        m_last = reg;
        ++m_len;
    }
    std::vector<Ret> callAll(Args && ...args)
    {
        std::vector<Ret> ret(m_len);
 
        FuncRegistry * reg = m_first;
        for(size_t i = 0; reg; reg = reg->next)
        {
            ret[i++] = reg->call(std::forward<Args>(args)...);
        }
        return ret;
    }
 
private:
    FuncRegistry * m_first;
    FuncRegistry * m_last;
    size_t         m_len;
};
/*----------------------------------------------------------------------------*/
template <typename File, typename FType>
FunctionReg<File, FType>::FunctionReg(FType f)
    : next(), call(f)
{
    FunctionStorage<File, FType>::instance().append(this);
}
/*----------------------------------------------------------------------------*/
template <typename FuncName, typename FileName>
struct FunctionEntry;
/*----------------------------------------------------------------------------*/
 
#define FUNCTION_DECL(FName, Body) \
template <typename FileName> \
struct FunctionEntry<MAKE_CT_STRING(#FName), FileName>                      \
{                                                                           \
    static auto FName Body;                                                 \
private:                                                                    \
    using  FuncReg = FunctionReg<FileName, decltype(FunctionEntry::FName)>; \
    static FuncReg reg;                                                     \
}; \
\
template class FunctionEntry<MAKE_CT_STRING(#FName), MAKE_CT_STRING(__FILE__)>; \
\
template <typename FileName>                                                  \
typename FunctionEntry<MAKE_CT_STRING(#FName), FileName>::FuncReg             \
            FunctionEntry<MAKE_CT_STRING(#FName), FileName>::reg(             \
                &FunctionEntry<MAKE_CT_STRING(#FName), FileName>::FName       \
            ); \
\
template <typename ...Args>          \
inline auto FName(Args && ...args)   \
{ return FunctionEntry<              \
            MAKE_CT_STRING(#FName)   \
          , MAKE_CT_STRING(__FILE__) \
         >::FName(std::forward<Args>(args)...); \
} \
\
template <typename FileName> \
auto FunctionEntry<MAKE_CT_STRING(#FName), FileName>::FName Body
 
#define CALL_ALL(Type, ...) \
    FunctionStorage<MAKE_CT_STRING(__FILE__), Type>::instance().callAll(__VA_ARGS__)
 
#define CALL_ALL_FROM(File, Type, ...) \
    FunctionStorage<MAKE_CT_STRING(File), Type>::instance().callAll(__VA_ARGS__)
 
#endif // FUNC_REGISTRY_H_INCLUDED

Использование:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <string>
#include <cstdio>
 
#include "func_registry.h"
 
FUNCTION_DECL(test1, (int a) -> std::string)
{
    return "test1!";
}
FUNCTION_DECL(test2, (int b) -> std::string)
{
    return "test2!";
}
FUNCTION_DECL(test3, (int c) -> std::string)
{
    return "test3!";
}
FUNCTION_DECL(test4, () -> int)
{
    return 42;
}
 
int main()
{
    auto v = CALL_ALL(std::string(int), 1);
    for(auto & c : v)
        std::printf("%s\n", c.c_str());
 
    auto l = CALL_ALL(int());
    for(auto & c : l)
        std::printf("%d\n", c);
}
Онлайн пример: http://rextester.com/QOF3281
 
Текущее время: 21:52. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru