Évidemment, nous pouvons concaténer deux littéraux de chaîne dans une constexpr
fonction, mais qu'en est-il de la concaténation d'un littéral de chaîne avec une chaîne renvoyée par une autre constexpr
fonction comme dans le code ci-dessous?
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>);
Le code rend l'identificateur de chaîne indépendant du compilateur d'un type arithmétique.
EDIT1:
Un exemple un peu plus compliqué est:
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
(et probablement + modèlestypeid
opérateur. Une partie de la raisontypeid
fait partie du langage (par exemple pris en charge par un mot-clé de langage dédié) plutôt qu'une fonction de bibliothèque est que l'implémentation repose sur la "magie du compilateur" - il n'est pas possible d'implémenter dans le langage sans un support dédié de l'implémentation .Réponses:
Voici une classe de chaîne de temps de compilation rapide:
vous pouvez l'utiliser comme ceci:
ce qui conduit à des déclarations comme:
qui passe.
Exemple en direct .
Maintenant, une chose ennuyeuse est que la longueur du tampon est dans le système de type. Vous pouvez ajouter un
length
champ et définirN
be "buffer size" et le modifierct_str
pour ne copier quelength
et laisser les octets de fin sous0
. Remplacez ensuitecommon_type
pour renvoyer le maximumN
des deux côtés.Cela vous permettrait de passer
ct_str{"uint"}
etct_str{"int"}
dans le même type de valeur et de rendre le code d'implémentation un peu moins ennuyeux.Les implémentations de fonctions deviennent maintenant:
ce qui est beaucoup plus naturel à écrire.
Exemple en direct .
la source
else
enget_arithmetic_size
avecif constexpr
même si vous le faitesreturn
, parce que sanselse
l'affirmationdependent_false_v<T>
échouera.Non c'est impossible. Vous pouvez implémenter quelque chose comme ci-dessous (c'est C ++ 14).
https://ideone.com/BaADaM
Si vous n'aimez pas utiliser
<cmath>
, vous pouvez remplacerstd::log
:la source
std::log
est trop compliqué pour moi, besoin d'une technique générique pour concaténer les cordesconstexpr
, ne t'inquiète passtd::log()
. Vous pouvez le remplacer, mais le code sera agrandi,std::log
nistd::strcmp
n'est garanti d'êtreconstexpr
. En fait, la norme leur interdit spécifiquement d'êtreconstexpr
depuis C ++ 14. Par conséquent, votre code utilise en fait des extensions non standard.