Obviamente podemos concatenar dos literales de cadena en una constexprfunción, pero ¿qué pasa con la concatenación de un literal de cadena con una cadena devuelta por otra constexprfunción como en el código a continuación?
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>);El código crea un identificador de cadena independiente del compilador de un tipo aritmético.
EDITAR1:
Un ejemplo un poco más complicado es:
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(y probablemente + plantillas variadas)typeidoperador. Parte de la razóntypeides parte del lenguaje (por ejemplo, respaldado por una palabra clave de idioma dedicada) en lugar de una función de biblioteca es que implementarlo se basa en la "magia del compilador": no es posible implementar en el lenguaje sin algún apoyo dedicado de la implementación .Respuestas:
Aquí hay una clase de cadena de tiempo de compilación rápida:
puedes usarlo así:
lo que lleva a declaraciones como:
paso.
Ejemplo en vivo .
Ahora, una cosa molesta es que la longitud del búfer está en el sistema de tipos. Puede agregar un
lengthcampo y hacer queNsea "tamaño de búfer", y modificarct_strpara copiar sololengthy dejar los bytes finales como0. Luego anulecommon_typepara devolver el máximoNde ambos lados.Eso le permitiría pasar
ct_str{"uint"}yct_str{"int"}en el mismo tipo de valor y hacer que el código de implementación sea un poco menos molesto.Las implementaciones de funciones ahora se convierten en:
lo cual es mucho más natural de escribir.
Ejemplo en vivo .
fuente
elseenget_arithmetic_sizeconif constexprincluso si lo hacereturn, porque sinelsela afirmacióndependent_false_v<T>fallará.No es imposible. Puede implementar algo como a continuación (es C ++ 14).
https://ideone.com/BaADaM
Si no le gusta usar
<cmath>, puede reemplazarstd::log:fuente
std::loges demasiado complicado para mí, necesito una técnica genérica para concatenar cadenasconstexpr, no te preocupesstd::log(). Puede reemplazarlo, pero el código se ampliará,std::lognistd::strcmpse garantiza que ni lo seaconstexpr. De hecho, el estándar específicamente les prohíbe serconstexprdesde C ++ 14. Por lo tanto, su código en realidad hace uso de extensiones no estándar.