Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 30.09.15 16:21
Оценка:
Заглянул в С++14, нашёл шаблонные переменные.

Тут же решил воплотить давнее желание — собрать указатели на все локальные строки в глобальный map, но уже на первом шаге получил ошибку: "error: use of deleted function".

Зато понял, что имена переменных могут включать в себя угловые скобки (бессмысленная возможность):
#include <iostream>
     
template<class T>
int len = 2;
     
template<class Fn>
const char* s_str = Fn();
     
//template<class Fn>
//auto x = Fn();
     
int main()
{
    class centimeter {};
    class meter {};
    class nothing {};
     
    len<centimeter> = 100 * len<meter>;
     
    std::cout << len<nothing> << ',' << len<centimeter> << std::endl;
     
    const char* str = "asdf";
     
    auto oGetStr = [str]()->const char* {return str;};
    //const char* p = s_str<decltype(oGetStr)>; // error
     
    auto o2and2 = []()->int{return 2 + 2;};
    //int n = x<decltype(o2and2)>; // error
     
    return 0;
}



Может уже появился какой способ собрать указатели на локальные строки в глобальных переменных ? (Например, шаблон параметризованный локальной строкой...)
И каждый день — без права на ошибку...
Re: Чудны способности твои, о стандарт !
От: Evgeny.Panasyuk Россия  
Дата: 30.09.15 16:27
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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


Поясни что нужно конкретно. Например передавать compile-time строки в шаблоны можно с некоторыми ухищрениями. А вот что ты понимаешь под "собрать"?
Re: Чудны способности твои, о стандарт !
От: VTT http://vtt.to
Дата: 30.09.15 16:37
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Заглянул в С++14, нашёл шаблонные переменные.


BFE>Тут же решил воплотить давнее желание — собрать указатели на все локальные строки в глобальный map


Что? Зачем?

BFE> но уже на первом шаге получил ошибку: "error: use of deleted function".


BFE>template<class Fn>

BFE>const char* s_str = Fn();

BFE> auto oGetStr = [str]()->const char* {return str;};

BFE> //const char* p = s_str<decltype(oGetStr)>; // error

decltype(oGetStr) выозвратит тип ламбды
в выражении справа будет вызваться конструктор? экземпляра этой ламбды
const char* s_str = Fn();

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


BFE>Зато понял, что имена переменных могут включать в себя угловые скобки (бессмысленная возможность):


Как это?
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[2]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 30.09.15 16:45
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

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

EP>Поясни что нужно конкретно. Например передавать compile-time строки в шаблоны можно с некоторыми ухищрениями. А вот что ты понимаешь под "собрать"?

Допусти, что все строки в программе обрамлены макросом:

void fun()
{
    std::cout << TT("asdf") << std::endl;
}


Можно ли сделать так, чтобы была создана глобальная переменная содержащая список всех таких строк. Это может быть полезно при переводе сообщений на другой язык.
И каждый день — без права на ошибку...
Re[2]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 30.09.15 16:48
Оценка:
Здравствуйте, VTT, Вы писали:

BFE>>Зато понял, что имена переменных могут включать в себя угловые скобки (бессмысленная возможность):

VTT>Как это?
В примере же есть:
len<centimeter> = 100 * len<meter>;

len<centimeter>
и
len<meter>
— это две разные переменные типа int.
И каждый день — без права на ошибку...
Re[3]: Чудны способности твои, о стандарт !
От: watchmaker  
Дата: 30.09.15 16:49
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Допусти, что все строки в программе обрамлены макросом:

BFE>Можно ли сделать так, чтобы была создана глобальная переменная содержащая список всех таких строк. Это может быть полезно при переводе сообщений на другой язык.

Но ведь уже 20 лет gettext работает именно таким образом.
Re[4]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 30.09.15 16:58
Оценка:
Здравствуйте, watchmaker, Вы писали:

BFE>>Допусти, что все строки в программе обрамлены макросом:

BFE>>Можно ли сделать так, чтобы была создана глобальная переменная содержащая список всех таких строк. Это может быть полезно при переводе сообщений на другой язык.

W>Но ведь уже 20 лет gettext работает именно таким образом.


Неужели? Я думал, что для использования gettext'а нужны сторонние утилиты.
И каждый день — без права на ошибку...
Re[3]: Чудны способности твои, о стандарт !
От: VTT http://vtt.to
Дата: 30.09.15 17:00
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>В примере же есть:

BFE>
BFE>len<centimeter> = 100 * len<meter>;
BFE>

BFE>len<centimeter>
BFE>и
BFE>len<meter>
BFE>- это две разные переменные типа int.

Тогда по вашей логике имена переменных могут включать пробелы, переносы строк, комментарии, макросы и прочее.
Можно же и так записать:
len<   /* пишем пишем*/
   centimeter
  > = 0;


Просто это не переменные а две специализации шаблона переменной, состоящие из имени шаблона и списков параметров шаблона, заключенных в угловые скобки.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Отредактировано 30.09.2015 17:01 VTT . Предыдущая версия .
Re[3]: Чудны способности твои, о стандарт !
От: Went  
Дата: 30.09.15 17:18
Оценка:
Здравствуйте, B0FEE664, Вы писали:
BFE>
BFE>void fun()
BFE>{
BFE>    std::cout << TT("asdf") << std::endl;
BFE>}
BFE>

BFE>Можно ли сделать так, чтобы была создана глобальная переменная содержащая список всех таких строк. Это может быть полезно при переводе сообщений на другой язык.
А что мешает определить TT как вызов функции, внутри которой живет глобальная переменная и дальше по тексту? Или нужна подстановка без поиска в словаре?
Re[4]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 30.09.15 17:26
Оценка:
Здравствуйте, Went, Вы писали:

BFE>>
BFE>>void fun()
BFE>>{
BFE>>    std::cout << TT("asdf") << std::endl;
BFE>>}
BFE>>

BFE>>Можно ли сделать так, чтобы была создана глобальная переменная содержащая список всех таких строк. Это может быть полезно при переводе сообщений на другой язык.
W>А что мешает определить TT как вызов функции, внутри которой живет глобальная переменная и дальше по тексту? Или нужна подстановка без поиска в словаре?

А откуда в этой функции известно, что строка "asdf" вообще существует?
И каждый день — без права на ошибку...
Re[4]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 30.09.15 17:37
Оценка: :)
Здравствуйте, VTT, Вы писали:

VTT>Тогда по вашей логике имена переменных могут включать пробелы, переносы строк, комментарии, макросы и прочее.

Кстати, да!

VTT>Можно же и так записать:

VTT>
VTT>len<   /* пишем пишем*/
VTT>   centimeter
  >> = 0;
VTT>


VTT>Просто это не переменные а две специализации шаблона переменной, состоящие из имени шаблона и списков параметров шаблона, заключенных в угловые скобки.

В том-то и дело, что тип таких переменных не зависит от их специализации. Просто у этих переменных имена сложные, составные.
И каждый день — без права на ошибку...
Re[5]: Чудны способности твои, о стандарт !
От: Went  
Дата: 30.09.15 18:59
Оценка:
Здравствуйте, B0FEE664, Вы писали:
BFE>А откуда в этой функции известно, что строка "asdf" вообще существует?
В смысле, что это строковой литерал, а не результат вызова (std::string("fu") + std::string("ck")).c_str()?
Re[5]: Чудны способности твои, о стандарт !
От: Went  
Дата: 30.09.15 19:08
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:
VTT>>Просто это не переменные а две специализации шаблона переменной, состоящие из имени шаблона и списков параметров шаблона, заключенных в угловые скобки.
BFE>В том-то и дело, что тип таких переменных не зависит от их специализации. Просто у этих переменных имена сложные, составные.
Ну, вроде бы шаблоны переменных вводили для типизированных констант и разных трейтов? Фактически, синтаксический сахар над:
// Вместо
template <typename F>
struct pi_traits
{
  static F get() {return (F)3.1415...;}
};
// Получаем:
template <typename F>
static const pi<F> = (F)3.1415...;

Не? Есть еще какие-то принципиально новые применения?
Re[6]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 30.09.15 21:30
Оценка: 36 (2)
Здравствуйте, Went, Вы писали:

VTT>>>Просто это не переменные а две специализации шаблона переменной, состоящие из имени шаблона и списков параметров шаблона, заключенных в угловые скобки.

BFE>>В том-то и дело, что тип таких переменных не зависит от их специализации. Просто у этих переменных имена сложные, составные.
W>Ну, вроде бы шаблоны переменных вводили для типизированных констант и разных трейтов? Фактически, синтаксический сахар над:
Это, да, но результат чудной.

W>Не? Есть еще какие-то принципиально новые применения?


А вот, только что придумал:
#include <iostream>
     
     
template<class T>
T x = T{};

void f()
{
    class Test{ public: Test(){std::cout << "Test\n";} };

    Test t = x<Test>;
}


int main()
{
    std::cout << "start\n";

    return 0;
}


Какой, думаете, будет вывод такой программы?

Похоже, что можно, таки, заставить выполнятся локальный код в глобальном пространстве. Возможно, что так было всегда, просто синтаксического сахара для мозгов не хватало...
И каждый день — без права на ошибку...
Re[7]: Чудны способности твои, о стандарт !
От: Evgeny.Panasyuk Россия  
Дата: 30.09.15 22:05
Оценка: :)
Здравствуйте, B0FEE664, Вы писали:

BFE>Какой, думаете, будет вывод такой программы?


Clang на Coliru выдал segfault.
Re[3]: Чудны способности твои, о стандарт !
От: Evgeny.Panasyuk Россия  
Дата: 30.09.15 22:19
Оценка: 3 (2) +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Допусти, что все строки в программе обрамлены макросом:

BFE>
BFE>void fun()
BFE>{
BFE>    std::cout << TT("asdf") << std::endl;
BFE>}
BFE>

BFE>Можно ли сделать так, чтобы была создана глобальная переменная содержащая список всех таких строк. Это может быть полезно при переводе сообщений на другой язык.

Если трюк описанный выше соответствует стандарту, то получается что-то типа:
#include <iostream>
#include <vector>

using namespace std;

vector<const char *> strings;

template<class T>
T run_it = T{};

#define GETTEXT(x) \
    [] \
    { \
        struct Action { Action() { strings.push_back(x); } };\
        (void)run_it<Action>; \
        return x; \
    }() \
/**/

void not_used()
{
    const char *x = GETTEXT("first");
    auto y = GETTEXT("second");
}

int main()
{    
    for(auto x : strings)
        cout << x << endl;
}
LIVE DEMO on Coliru GCC:
first
second
Re[8]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 01.10.15 08:34
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

BFE>>Какой, думаете, будет вывод такой программы?

EP>Clang на Coliru выдал segfault.
ideone выдаёт

Test
start


Пойду, посмотрю, что по этому поводу говорит стандарт.
PS Ничего криминального не нашёл. Вроде бы пример корректный.
И каждый день — без права на ошибку...
Отредактировано 01.10.2015 9:20 B0FEE664 . Предыдущая версия .
Re[8]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 01.10.15 09:30
Оценка: 14 (1)
Здравствуйте, Evgeny.Panasyuk, Вы писали:

BFE>>Какой, думаете, будет вывод такой программы?

EP>Clang на Coliru выдал segfault.
Возможно это связано с инициализацией std::cout.

вот так работает
И каждый день — без права на ошибку...
Re[4]: Чудны способности твои, о стандарт !
От: T4r4sB Россия  
Дата: 01.10.15 09:35
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Если трюк описанный выше соответствует стандарту, то получается что-то типа:


Объясните мне, пожалуйста, в какой момент выполняется код добавления строки в хранилище.
При инициализации глобальной переменной run_it<Action>? А код в неиспользуемой функции как бы говорит, что такая глобальная перемення существует?

Забавно, из локального блока объявить глобальную переменную.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 01.10.2015 9:37 T4r4sB . Предыдущая версия .
Re[5]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 01.10.15 10:12
Оценка:
Здравствуйте, T4r4sB, Вы писали:

EP>>Если трюк описанный выше соответствует стандарту, то получается что-то типа:

TB>Объясните мне, пожалуйста, в какой момент выполняется код добавления строки в хранилище.
TB>При инициализации глобальной переменной run_it<Action>?
да.
TB> А код в неиспользуемой функции как бы говорит, что такая глобальная перемення существует?
да, можно и так сказать.

TB>Забавно, из локального блока объявить глобальную переменную.

Забавно не это, а то, что можно выполнить кусочек локального кода из вне.
И каждый день — без права на ошибку...
Re[4]: trick
От: B0FEE664  
Дата: 01.10.15 11:05
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

Вот такой вариант работает и для стандарта С++14, и в Visual Studio 2013:
#include <iostream>
#include <vector>

std::vector<const char*> g_Strings;

const char* AddToGlobalArray(const char* pStr)
{
  g_Strings.push_back(pStr);
  return pStr;
}


template <class T>
class StrMap
{
  public:
    static const char* const m_p;
};

//static
template <class T>
const char* const StrMap<T>::m_p = AddToGlobalArray(T().get());

void fun()
{
    struct GetStr{ const char* get() { return "asdf"; } };

    const char* p = StrMap<GetStr>::m_p;
}


void fun2()
{
    struct GetStr{ const char* get() { return "qwerty"; } };

    const char* p = StrMap<GetStr>::m_p;
}


int main(int argc, char* argv[])
{
    for(auto x : g_Strings)
        std::cout << x << std::endl;

    return 0;
}


Output:
asdf
qwerty
И каждый день — без права на ошибку...
Re[5]: trick
От: Evgeny.Panasyuk Россия  
Дата: 01.10.15 13:05
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Вот такой вариант работает и для стандарта С++14, и в Visual Studio 2013:


Да, здорово, вот только на Clang что-то не заводится.
Хотя два из трёх компиляторов это уже серьёзно.
Re[6]: trick
От: T4r4sB Россия  
Дата: 01.10.15 13:13
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:


EP>Да, здорово, вот только на Clang что-то не заводится.


Судя по выхлопу, strings очищается перед вызовом мейна?!
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[7]: trick
От: Evgeny.Panasyuk Россия  
Дата: 01.10.15 13:34
Оценка:
Здравствуйте, T4r4sB, Вы писали:

EP>>Да, здорово, вот только на Clang что-то не заводится.

TB>Судя по выхлопу, strings очищается перед вызовом мейна?!

Видимо не очищается, а просто конструируется позже run_it, хотя по идее должен раньше (можно попробовать сделать тест с порядком вызова конструкторов).
С синглтоном Майерса работает и на Clang.
Отредактировано 01.10.2015 13:35 Evgeny.Panasyuk . Предыдущая версия . Еще …
Отредактировано 01.10.2015 13:34 Evgeny.Panasyuk . Предыдущая версия .
Re[8]: trick
От: Evgeny.Panasyuk Россия  
Дата: 01.10.15 13:40
Оценка:
EP>Видимо не очищается, а просто конструируется позже run_it, хотя по идее должен раньше (можно попробовать сделать тест с порядком вызова конструкторов).

Да, именно так и происходит:
#include <cstdio>

using namespace std;

struct First
{
    First()
    {
        printf("first\n");
    }
} first;

template<class T>
T run_it = T{};

void not_used()
{
    struct Second
    {
        Second()
        {
            printf("second\n");
        }
    };
    Second t = run_it<Second>;
}

int main()
{
}

// GCC:
first
second

// Clang:
second
first
Re[7]: Чудны способности твои, о стандарт !
От: flаt  
Дата: 02.10.15 08:22
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>А вот, только что придумал:


BFE>template<class T>

BFE>T x = T{};

BFE> Test t = x<Test>;


Кто разъяснит, как это работает? Ведь до инициализации Test исполнение кода не доходит, почему же T<> инициализируется?
Какая связь между инстанцированием шаблона (T, StrMap) в локальном коде и инициализацией глобальной переменной?

Куда ткнуться почитать?
Re[8]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 02.10.15 09:42
Оценка: 4 (1)
Здравствуйте, flаt, Вы писали:

BFE>>А вот, только что придумал:

BFE>>template<class T>
BFE>>T x = T{};

BFE>> Test t = x<Test>;


F>Кто разъяснит, как это работает? Ведь до инициализации Test исполнение кода не доходит, почему же T<> инициализируется?

F>Какая связь между инстанцированием шаблона (T, StrMap) в локальном коде и инициализацией глобальной переменной?

x — это глобальная переменная, следовательно она должна быть инициализирована в глобальном пространстве. То, что определение класса лежит где-то ещё не столь важно.
Дело тут даже не столько в том, что введены шаблонные переменные, а в том, что теперь в качестве параметра шаблона можно указать локальный класс. В сообщении trick, выше, это видно.
С этим кодом, кстати, возможна проблема из-за порядка инициализации глобальных переменных. Для надёжности, x следует сделать константой: const T x = T{};

F>Куда ткнуться почитать?

Не знаю, я стандарт просматривал...
И каждый день — без права на ошибку...
Re: Чудны способности твои, о стандарт !
От: wander  
Дата: 02.10.15 11:11
Оценка: 14 (2)
Здравствуйте, 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
Может быть будет полезно.
Отредактировано 02.10.2015 11:14 wander (Опечатки) . Предыдущая версия .
Re[2]: Чудны способности твои, о стандарт !
От: Evgeny.Panasyuk Россия  
Дата: 02.10.15 11:37
Оценка: 6 (1)
Здравствуйте, wander, Вы писали:

W>Вспомогательная кухня, применил тут кое-какие свои давние идеи по реализации настоящих ct-строк:


Хм, а насколько вот такой код соответствует стандарту?
int main()
{
    struct X
    {
        const char *chars = "abc";
    };
    static_assert(X{}.chars[0] == 'a', "");
    constexpr char x = X{}.chars[0];
}

Clang и GCC компилируют. Но разве X{}.chars[0] в этом случае constexpr?

Я в подобном случае
Автор: Evgeny.Panasyuk
Дата: 12.10.14
использовал constexpr метод:
#define CTTE_WRAP_STRING(x) \
    [] \
    { \
        struct { static constexpr auto value() { return x;} } str; \
        return str; \
    } \
/**/
Re[3]: Чудны способности твои, о стандарт !
От: Evgeny.Panasyuk Россия  
Дата: 02.10.15 11:52
Оценка:
EP>
EP>    struct X
EP>    {
EP>        const char *chars = "abc";
EP>    };
EP>


Видимо дело в том что это равнозначно:
    struct X
    {
        const char *chars;
        
        constexpr X() : chars("abc") {}
    };
Re[4]: Чудны способности твои, о стандарт !
От: wander  
Дата: 02.10.15 13:10
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>>
EP>>    struct X
EP>>    {
EP>>        const char *chars = "abc";
EP>>    };
EP>>


EP>Видимо дело в том что это равнозначно:

EP>
EP>    struct X
EP>    {
EP>        const char *chars;
        
EP>        constexpr X() : chars("abc") {}
EP>    };
EP>


Да, именно.
Насчет constexpr функции с auto — то это работает только в С++14.
А приемы эти я изобретал еще на C++0x.
Можно применить вот такой вариант для С++11, если все еще есть сомнения насчет легитимности.
struct X
{
    typedef decltype("abc") type;
    static constexpr type chars() { return "abc"; }
};
Re[3]: Чудны способности твои, о стандарт !
От: wander  
Дата: 02.10.15 13:19
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Я в подобном случае
Автор: Evgeny.Panasyuk
Дата: 12.10.14
использовал constexpr метод:


Спасибо за ссылку. Не видел.
Сразу уже вижу, что ты исследование провел более полное, чем я в свое время
Re[5]: Чудны способности твои, о стандарт !
От: Evgeny.Panasyuk Россия  
Дата: 02.10.15 13:33
Оценка:
Здравствуйте, wander, Вы писали:

W>Насчет constexpr функции с auto — то это работает только в С++14.


Его можно без проблем заменить на const char *, auto там исключительно для удобства.
Там всё равно размер вычисляется через:
constexpr std::size_t c_str_length(const char *x)
{
    return find(x, '\0') - x;
}


W>Можно применить вот такой вариант для С++11, если все еще есть сомнения насчет легитимности.

W>
W>struct X
W>{
W>    typedef decltype("abc") type;
W>    static constexpr type chars() { return "abc"; }
W>};
W>


Или другой C++11 вариант:
struct X
{
    static constexpr auto chars() -> decltype("abc")
    {
        return "abc";
    }
};
Re[6]: Чудны способности твои, о стандарт !
От: wander  
Дата: 02.10.15 13:43
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Его можно без проблем заменить на const char *, auto там исключительно для удобства.


Точно не вспомню пример, но иногда это не работало.
Возможно это были временные баги компиляторов, не помню уже.
Последний раз с этим всерьез возился кажется в 12 году.
Re[6]: Чудны способности твои, о стандарт !
От: wander  
Дата: 02.10.15 13:57
Оценка:
Здравствуйте, Evgeny.Panasyuk:

В общем, я тогда остановился вот на таком варианте, как на наиболее подходящем:
    #define DECL_STR(str) \
        struct { char const * chars = (str); }

    using test = DECL_STR("test");
Re[3]: Чудны способности твои, о стандарт !
От: wander  
Дата: 05.10.15 09:47
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Clang и GCC компилируют.


VS 2015, кстати, тоже.
Вообще весь код без изменений (почти, см. ниже) работает в 2015.
Проверял тут: http://webcompiler.cloudapp.net/

Изменения:
template <typename Str, size_t ...I>
struct string_gen<Str, ::ct::indices<I...>>
    : ::ct::string<Str().chars[I]...> // Str{} -> Str()
{ };
Re[5]: Чудны способности твои, о стандарт !
От: rus blood Россия  
Дата: 05.10.15 11:37
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>В том-то и дело, что тип таких переменных не зависит от их специализации. Просто у этих переменных имена сложные, составные.


А в len<meter> можно явно/неявно присвоить len<centimeter> ?
Имею скафандр — готов путешествовать!
Re[6]: Чудны способности твои, о стандарт !
От: B0FEE664  
Дата: 05.10.15 12:00
Оценка: 4 (1) +1
Здравствуйте, rus blood, Вы писали:

BFE>>В том-то и дело, что тип таких переменных не зависит от их специализации. Просто у этих переменных имена сложные, составные.

RB>А в len<meter> можно явно/неявно присвоить len<centimeter> ?

Да. Можно явно присвоить. len<meter> = len<centimeter>; присвоит значение len<centimeter> в len<meter>. Поэтому я и говорю, что это просто имена переменных.
И каждый день — без права на ошибку...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.