Очевидно, что мы можем объединить два строковых литерала в constexpr
функции, но как насчет объединения строкового литерала со строкой, возвращенной другой constexpr
функцией, как в коде ниже?
template <class T>
constexpr const char * get_arithmetic_size()
{
switch (sizeof(T))
{
case 1: return "1";
case 2: return "2";
case 4: return "4";
case 8: return "8";
case 16: return "16";
default: static_assert(dependent_false_v<T>);
}
}
template <class T>
constexpr std::enable_if_t<std::is_arithmetic_v<T>, const char *> make_type_name()
{
const char * prefix = std::is_signed_v<T> ? "int" : "uint";
return prefix; // how to concatenate prefix with get_arithmetic_size<T>() ?
}
static_assert(strings_equal(make_type_name<int>, make_type_name<int32_t>);
Код делает независимый от компилятора строковый идентификатор арифметического типа.
EDIT1:
Немного более сложный пример:
template<typename Test, template<typename...> class Ref>
struct is_specialization : std::false_type {};
template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
template <class T>
constexpr std::enable_if_t<is_specialization<T, std::vector>::value || is_specialization<T, std::list>::value, const char *> make_type_name()
{
return "sequence"; // + make_type_name<typename T::value_type>;
}
static_assert(strings_equal(make_type_name<std::vector<int>>(), make_type_name<std::list<int>>()));
std::array
(и, вероятно, + вариационные шаблоны)typeid
оператор. Частично причинаtypeid
заключается в том, что часть языка (например, поддерживается специальным ключевым словом языка), а не библиотечная функция, заключается в том, что ее реализация опирается на «магию компилятора» - невозможно реализовать на языке без специальной поддержки со стороны реализации. ,Ответы:
Вот класс строки времени быстрой компиляции:
Вы можете использовать это так:
что приводит к таким заявлениям, как:
прохождение.
Живой пример .
Теперь одна неприятная вещь заключается в том, что длина буфера находится в системе типов. Вы можете добавить
length
поле, сделатьN
его "размером буфера" и изменить его,ct_str
чтобы копировать только доlength
и оставлять конечные байты как0
. Затем переопределите,common_type
чтобы вернуть максимумN
обеих сторон.Это позволило бы вам передать
ct_str{"uint"}
и значениеct_str{"int"}
того же типа и сделать код реализации немного менее раздражающим.Реализации функций теперь становятся:
что гораздо естественнее для написания.
Живой пример .
источник
else
вget_arithmetic_size
с ,if constexpr
даже если вы делаетеreturn
, потому что безelse
утверждениеdependent_false_v<T>
не удастся.Нет, это невозможно. Вы можете реализовать что-то вроде ниже (это C ++ 14).
https://ideone.com/BaADaM
Если вам не нравится использовать
<cmath>
, вы можете заменитьstd::log
:источник
std::log
это слишком сложно для меня, нужна некоторая общая техника для объединения строкconstexpr
не беспокойсяstd::log()
. Вы можете заменить его, но код будет увеличен,std::log
ниstd::strcmp
гарантированно не будетconstexpr
. Фактически, стандарт специально запрещает им бытьconstexpr
с C ++ 14. Следовательно, ваш код на самом деле использует нестандартные расширения.