строковый литерал в шаблон?
От: Кодт Россия  
Дата: 06.09.23 11:32
Оценка:
Ищу способ протащить строковый литерал в тип кроссплатформенно.

И что-то запутался!
cppreference, а также MSDN утверждают, что вот такой синтаксис литеральных операторов правильный
template<char... Cs> auto operator "" _MY_SUFFIX ()

однако ни gcc, ни clang, ни msvc его не жруть!

template<class T, T... Cs> auto operator "" _MY_SUFFIX ()

gcc жрёт, clang говорит, что это гнутое расширение, но всё равно жрёт, а msvc опять не жрёт.

Видел на stackoverflow какие-то монструозные решения с макросами. Хотелось бы что-нибудь в три строчки.


И кстати, где-нибудь есть онлайн-компилятор msvc, тянущий 20 стандарт? На godbolt, кажется, максимум — это 17.
Перекуём баги на фичи!
Re: строковый литерал в шаблон?
От: reversecode google
Дата: 06.09.23 11:36
Оценка: 35 (1)
К>И кстати, где-нибудь есть онлайн-компилятор msvc, тянущий 20 стандарт? На godbolt, кажется, максимум — это 17.

а если не выдумывать а проверить?
19.37+

но выхлом msvc непокажет
только возможность скомпилить
Re: строковый литерал в шаблон?
От: reversecode google
Дата: 06.09.23 11:46
Оценка: 36 (2)
первый попавшйся пример из гугла компилит
правда статик ассерт не проходит в msvc
у кланга проходит
но вы умный
разберетесь
https://godbolt.org/z/zEKnoefhW
Re: строковый литерал в шаблон?
От: vopl Россия  
Дата: 06.09.23 12:00
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Ищу способ протащить строковый литерал в тип кроссплатформенно.


Заходил на этот вопрос не через литералы, но просто через CTAD на шаблонную обертку, инстанция которой используется как non-type template argument. Получается довольно приятно.

обертка https://github.com/vopl/dci-core-qml/blob/master/include/dci/qml/qmeta/common.hpp#L26-L46
использование в шаблоне https://github.com/vopl/dci-core-qml/blob/master/include/dci/qml/qmeta/api/prop.hpp#L56
использование в инстанции https://github.com/vopl/dci-core-qml/blob/master/include/dci/qml/qmeta/def/cmtFuture.hpp#L96
Re[2]: строковый литерал в шаблон?
От: vopl Россия  
Дата: 06.09.23 12:06
Оценка: 112 (2)
Здравствуйте, vopl, Вы писали:

V>Здравствуйте, Кодт, Вы писали:


К>>Ищу способ протащить строковый литерал в тип кроссплатформенно.


V>Заходил на этот вопрос не через литералы, но просто через CTAD на шаблонную обертку, инстанция которой используется как non-type template argument. Получается довольно приятно.


V>обертка https://github.com/vopl/dci-core-qml/blob/master/include/dci/qml/qmeta/common.hpp#L26-L46

V>использование в шаблоне https://github.com/vopl/dci-core-qml/blob/master/include/dci/qml/qmeta/api/prop.hpp#L56
V>использование в инстанции https://github.com/vopl/dci-core-qml/blob/master/include/dci/qml/qmeta/def/cmtFuture.hpp#L96

дистилят https://gcc.godbolt.org/z/db1of6q8G
Re[3]: строковый литерал в шаблон?
От: Кодт Россия  
Дата: 06.09.23 13:37
Оценка:
Здравствуйте, vopl, Вы писали:

V>дистилят https://gcc.godbolt.org/z/db1of6q8G


то что доктор прописал.

Оказывается, для уникальной идентификации надо копировать строку внутрь типа.

Бидистиллят:
#include <cstdint>
#include <type_traits>

template<std::size_t N> struct S {
    char buf[N];
    constexpr S(const char(&b)[N]) {
        for (std::size_t i = 0; i != N; ++i) buf[i] = b[i];
    }
};
template<std::size_t N> S(const char(&)[N]) -> S<N>;

template<S s> struct TAG {};

static_assert(std::is_same_v<TAG<"aaa">, TAG<"aaa">>);
static_assert(!std::is_same_v<TAG<"aaa">, TAG<"bbb">>);
static_assert(!std::is_same_v<TAG<"aaa">, TAG<"bbb1">>);
Перекуём баги на фичи!
Re[2]: строковый литерал в шаблон?
От: Кодт Россия  
Дата: 06.09.23 13:40
Оценка:
Здравствуйте, reversecode, Вы писали:

R>а если не выдумывать а проверить?

R>19.37+

Прикольно, там вначале идут несколько древних WINE-версий, я на них спотыкался и ниже не скроллил.
Перекуём баги на фичи!
Re[3]: строковый литерал в шаблон?
От: reversecode google
Дата: 06.09.23 14:28
Оценка:
там бывают не то глюки нето непонятно что
когда выбор компиллеров достаточно мал
но это бывает когда открываешь уже готовый линк
когда открываешь чисто сайт с нуля, таких глюков не бывает
Re: строковый литерал в шаблон?
От: Sm0ke Россия ksi
Дата: 06.09.23 15:48
Оценка: 77 (2)
Уже ответили, тем не менее)

Вариант 1


link: https://godbolt.org/z/j3M39odM6
#include <iostream>
#include <utility>

template <typename T, std::size_t N>
struct static_text
{
  T data[N];

  constexpr static_text(T (&s)[N]) : static_text(s, std::make_index_sequence<N>{}) {}
  
  template <std::size_t ... I>
  constexpr static_text(T (&s)[N], std::index_sequence<I ...>) : data{s[I] ...} {}
};

template <static_text S>
struct TAG
{};

//

int main()
{
    static_assert(std::is_same_v< TAG<"123">, TAG<"123"> >);
    return 0;
}


Вариант 2


Через std::array ~ https://godbolt.org/z/3hs7v4Y7d
#include <iostream>
#include <array>
#include <utility>

struct to_array_t {
  template <typename T, std::size_t N, std::size_t ... I>
  static inline constexpr std::array<T, N> helper(T (&s)[N], std::index_sequence<I ...>)
  { return {s[I] ...}; }
};

constexpr to_array_t to_array{};

template <typename T, std::size_t N>
constexpr std::array<T, N> operator * (T (&s)[N], to_array_t)
{ return to_array_t::helper(s, std::make_index_sequence<N>{});  }

//

template <std::array S>
struct TAG_ARRAY
{};

//

int main()
{
    static_assert(std::is_same_v< TAG_ARRAY<"123"*to_array>, TAG_ARRAY<"123"*to_array> >);
    return 0;
}
Re[2]: жаль в msvc пока так нельзя:
От: Sm0ke Россия ksi
Дата: 06.09.23 15:51
Оценка:
жаль в msvc пока так нельзя:

link: https://godbolt.org/z/vn8jqzYqz
#include <iostream>
#include <array>

template <typename T, T ... S>
constexpr std::array<T, sizeof...(S)> operator "" _ar ()
{ return {S ...}; }

template <std::array S>
struct TAG
{};

//

int main()
{
    static_assert(std::is_same_v< TAG<"123"_ar>, TAG<"123"_ar> >);
    return 0;
}
Re[3]: жаль в msvc пока так нельзя:
От: Кодт Россия  
Дата: 07.09.23 13:26
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>жаль в msvc пока так нельзя:

Это как раз то, о чём я в самом начале написал. И это — нестандартное, гнутое расширение. Шланг на него варнинги показывает.
Перекуём баги на фичи!
Re[4]: литерал
От: Sm0ke Россия ksi
Дата: 07.09.23 14:05
Оценка:
Здравствуйте, Кодт, Вы писали:

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


S>>жаль в msvc пока так нельзя:

К>Это как раз то, о чём я в самом начале написал. И это — нестандартное, гнутое расширение. Шланг на него варнинги показывает.

Если всё же нужен перегруженный литеральный суффикс оператор для текста, то это можно сделать так:

link: https://godbolt.org/z/nTvhbonrf
проверил на ms, clang, gcc
#include <utility>

template <typename T, std::size_t N>
struct static_text
{
  T data[N];

  constexpr static_text(T (&s)[N]) : static_text(s, std::make_index_sequence<N>{}) {}
  
  template <std::size_t ... I>
  constexpr static_text(T (&s)[N], std::index_sequence<I ...>) : data{s[I] ...} {}
};

template <static_text S>
constexpr auto operator "" _st ()
{ return S; }

//

template <static_text S>
struct TAG {};

//

int main()
{
  static constexpr static_text cv = "123"_st;
  static_assert(std::is_same_v< TAG<"123">, TAG<"123"> >);
  return 0;
}
Re[5]: литерал
От: Кодт Россия  
Дата: 07.09.23 17:48
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Если всё же нужен перегруженный литеральный суффикс оператор для текста, то это можно сделать так:


S>link: https://godbolt.org/z/nTvhbonrf

S>проверил на ms, clang, gcc

Можно даже без танцев с index_sequence.
template <std::size_t N> struct static_text
{
  char data[N];
  constexpr static_text(const char (&s)[N]) {
    for (std::size_t i = 0; i != N; ++i) data[i] = s[i];
  }
};


https://godbolt.org/z/rYj9Esx3j

(Да и тип char вполне можно приколотить)
Перекуём баги на фичи!
Re[5]: литерал
От: Кодт Россия  
Дата: 07.09.23 17:51
Оценка:
Здравствуйте, Sm0ke, Вы писали:
S>template <static_text S>
S>constexpr auto operator "" _st ()
S>{ return S; }

Забавно, что msvc только вот такой параметр шаблона оператора принимает.
А если там будет <char...> — то это только для чисел — 123_st. Ллогика, чёрт её дери.
Перекуём баги на фичи!
Re[5]: cout data OR string_view
От: Sm0ke Россия ksi
Дата: 08.09.23 21:29
Оценка:
При выводе в cout мембер data, то clang вызывает strlen
Но если выдать string_view, то в регистр пишется константа длинны

lnk: https://godbolt.org/z/M14oGv81f
#include <iostream>
#include <type_traits>
#include <string_view>

template <std::size_t N> struct static_text
{
  char data[N];
  constexpr static_text(const char (&s)[N]) {
    for (std::size_t i = 0; i != N; ++i) { data[i] = s[i]; }
  }
  constexpr std::string_view sv() const { return {data, N}; }
};

template <static_text S> constexpr auto operator "" _st () { return S; }

//

template <static_text S>
struct TAG {};

//

int main()
{
  static constexpr static_text cv = "123"_st;
  static_assert(std::is_same_v< TAG<"123">, TAG<cv> >);
  static_assert(!std::is_same_v< TAG<"456">, TAG<cv> >);
  //static_text tv = "1234"_st;
  std::cout << cv.sv() << '\n';
  std::cout << cv.data << '\n';
  return 0;
}


        mov     edx, 4
        call    std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)

        call    strlen
        mov     edi, offset std::cout
        mov     esi, offset main::cv
        mov     rdx, rax
        call    std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
Отредактировано 08.09.2023 22:33 Sm0ke . Предыдущая версия . Еще …
Отредактировано 08.09.2023 22:32 Sm0ke . Предыдущая версия .
Отредактировано 08.09.2023 22:32 Sm0ke . Предыдущая версия .
Re: строковый литерал в шаблон?
От: r0nd  
Дата: 11.09.23 17:50
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Ищу способ протащить строковый литерал в тип кроссплатформенно.


А в каких случаях это нужно/удобно? Короче, для чего такое писать? Можно пример/сниппет?
...<< Dementor 1.4.1 ✪ Lets Play a Game ⚁⚂⚃⚃⚅>>
Re[2]: строковый литерал в шаблон?
От: vopl Россия  
Дата: 12.09.23 08:33
Оценка: 4 (1)
Здравствуйте, r0nd, Вы писали:

R>Здравствуйте, Кодт, Вы писали:


К>>Ищу способ протащить строковый литерал в тип кроссплатформенно.


R>А в каких случаях это нужно/удобно? Короче, для чего такое писать? Можно пример/сниппет?


Если надо часть работы со строками вынести в компайл-тайм. Например, http-сервер, которому надо быстро парсить входящие запросы, состоящие из текстовых заголовков — вот для них было бы удобно в компайл-тайме завести образцы, для каждого подготовить lower-case вариант, посчитать хэши и сразу упаковать их в константную таблицу поиска в компайл-тайме, чтобы максимально разгрузить рантайм, чтоб там все побыстрее работало
https://github.com/vopl/adel/blob/master/include/http/headerName.hpp#L31
Re[2]: строковый литерал в шаблон?
От: Кодт Россия  
Дата: 13.09.23 15:44
Оценка: 4 (1)
Здравствуйте, r0nd, Вы писали:

R>А в каких случаях это нужно/удобно? Короче, для чего такое писать? Можно пример/сниппет?


Да вот, сделал для своих и студенческих нужд маленькую библиотечку юнит-тестов из единственного хедера.
https://github.com/nickolaym/simple_test
(такой гуглтест на минималках)

И меня сперва очень бесили все эти макросы EXPECT_EQ, EXPECT_LT, ...
Сделал макрос EXPECT_CMP(left, op, right)
где op — это операторы сравнения.

Подход вида
#define EXPECT_CMP(left, op, right) \
  SOMEHOW_COMPARE_AND_REPORT( \
    #left,  left, \
    #right, right, \
    #op, [](const auto& a, const auto& b) { return a op b; } \
  )

прост, но плох тем, что у каждого вызова EXPECT_CMP создаётся свой уникальный анонимный класс лямбды и свой уникальный экземпляр функции сравнения.

Даже если все вызовы EXPECT_CMP — над одними и теми же типами аргументов и с одними и теми же операциями.

Вместо const auto& можно написать что-то вида
[](const decltype(left)& a, const decltype(right)& b) { return a, b; }

ну, будет не полиморфная, но всё равно уникальная функция.

Поэтому захотел #op протащить в систему типов.
Набор операторов у нас конечный, нагенерить экземпляры по шаблону труда не составит

template< SomeTag > class comparator;

#define DECLARE_COMPARATOR(op) \
  template<> class comparator< TAG(#op) > { \
    auto operator()(const auto& a, const auto& b) { return a op b; } \
  };

DECLARE_COMPARATOR(==)
DECLARE_COMPARATOR(!=)
.....


#define USE_COMPARATOR(op) comparator< TAG(#op) >{} /* (left, right) */
Перекуём баги на фичи!
Re[3]: строковый литерал в шаблон?
От: reversecode google
Дата: 13.09.23 16:26
Оценка:
думал сейчас как открою репу
а там под восемсот тысяч звезд
и таких как минимум десяток звездных проектов
открыл
и ахнул
Re[4]: строковый литерал в шаблон?
От: Кодт Россия  
Дата: 14.09.23 19:19
Оценка:
Здравствуйте, reversecode, Вы писали:

R>думал сейчас как открою репу

R>а там под восемсот тысяч звезд
R>и таких как минимум десяток звездных проектов
R>открыл
R>и ахнул

Да ну нафиг. У меня на пет-проекты времени вообще нет, а эту либу стал делать, потому что надоело смотреть, как первокурсники сдают код с недоделками — "ой первый же assert() упал и у меня лапки".
Гуглтест — штука тяжеловесная, на мак ставить так вообще бубен нужен, а один файлик в папку кинуть — дурак справится.
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.