2017-07-26 3 views
4

J'ai un ancien code qui utilise quelque chose de très similaire à str_const décrit here et here pour faire une manipulation de chaîne constexpr. str_const est un type littéral décrit par Scott Schurr qui peut être construit à partir d'un littéral de chaîne, car il a un constructeur de modèle de const char (&)[].Convertir `hana :: string` en` constexpr const char (&) [] `

J'ai maintenant aussi du nouveau code en utilisant boost::hana.

Je voudrais pouvoir prendre un hana::string et créer un str_const qui fait référence à lui. Le moyen le plus simple de le faire est de convertir un hana::string en constexpr const char (&)[]. (En fait, à ce stade, ce n'est pas le plus simple, le plus simple est sûrement d'ajouter un nouveau constructeur de template à mon implémentation str_const. Mais à ce stade, la question a pris une vie propre et je m'intéresse principalement à savoir si cela peut être fait avec hana::string. donc, supposons que je ne suis pas autorisé à changer la mise en œuvre str_const.)

Cependant, hanadocs la façon de convertir hana::string à une chaîne d'exécution est hana::to<const char *>.

Optimalement, j'ai essayé différentes formes de hana::to<const char (&)[hana::length(...)]> (...) mais cela provoque des assertions statiques dans hana échouer.

L'autre option suggérée par hana docs est d'utiliser hana::unpack puis de coller moi-même les caractères dans un tableau. J'ai écrit ce code

template <typename T, size_t N> 
struct array { 
    T arr[N]; 
}; 

struct char_packer { 
    template <typename... Ts> 
    constexpr auto operator()(Ts... ts) -> array<const char, sizeof...(ts) + 1> { 
    return array<const char, sizeof...(ts) + 1>{{ ts... , 0 }}; 
    } 
}; 

template <typename S> 
struct string_keeper { 
    static constexpr auto my_array = hana::unpack(S{}, char_packer{}); 
}; 

template <int N> 
using char_arr = const char [N]; 

template <typename S> 
constexpr auto to_string_literal(S &&) -> const char_arr<decltype(hana::length(S{}))::value + 1> & { 
    return string_keeper<S>::my_array.arr; 
} 

Je pense que cela fonctionne presque, au moins, il compile. Mais si les références sont également utilisées lors de l'exécution, elle échoue avec une erreur de l'éditeur de liens: undefined reference to ... string_keeper<boost::hana::string<(char)97> >::my_array.

(En fait, je pense que je comprends pourquoi c'est un problème ODR et si je pense à ce sujet un peu plus je pourrais rappeler comment le résoudre ... pas sûr ...)

Intuitivement, je me sens qu'il y doit être un moyen de le faire. Parce que, hana me permet déjà de convertir hana::string en constexpr const char * où le pointeur pointe exactement sur le tableau que je veux. En fait, il suggère même qu'il pourrait y avoir une mauvaise option où j'essaye de contraindre le const char * à revenir au type const char *, bien que cela semble aussi qu'il faudrait faire des choses qui ne seront pas permises dans les fonctions constexpr. Quoi qu'il en soit, si hana peut faire ce tableau alors sûrement je peux aussi, ou en quelque sorte le convaincre de me le donner plus exactement.

Existe-t-il un moyen de réparer mon code ci-dessus? Y a-t-il un moyen plus facile de le faire au sein de hana que j'ai oublié? Est-ce réellement impossible pour une raison quelconque?

Répondre

1

Un autre problème est que, lorsqu'il est renvoyé par une fonction, un tableau de caractères brut est décomposé en pointeur. Je suggère de construire l'objet str_const dans le contexte de votre fonction qui, je crois, remplit votre intention de créer str_const sans changer son interface.

L'exemple suivant utilise un modèle variable de haut niveau pour créer le tableau qui est ce que la mise en œuvre hana::string utilise:

#define BOOST_HANA_CONFIG_ENABLE_STRING_UDL 
#include <boost/hana.hpp> 
#include <stdexcept> 

namespace hana = boost::hana; 
using namespace hana::literals; 

class str_const { 
    const char * const p_; 
    const std::size_t sz_; 
public: 
    template <std::size_t N> 
    constexpr str_const(const char(& a)[ N ]) 
    : p_(a), sz_(N - 1) {} 
    constexpr char operator[](std::size_t n) const { 
     return n < sz_ ? p_[ n ] : throw std::out_of_range(""); 
    } 
    constexpr std::size_t size() const { return sz_; } 
}; 

template <char ...c> 
constexpr char string_storage[sizeof...(c) + 1] = {c..., '\0'}; 

struct to_str_const_helper { 
    template <typename ...Ts> 
    constexpr auto operator()(Ts...) { 
    return str_const(string_storage<Ts::value...>); 
    } 
}; 
template <typename S> 
constexpr auto to_str_const(S) { 
    return hana::unpack(S{}, to_str_const_helper{}); 
} 

int main() 
{ 
    constexpr str_const str = to_str_const("foo"_s); 
    static_assert(str[0] == 'f', ""); 
    static_assert(str[1] == 'o', ""); 
    static_assert(str[2] == 'o', ""); 
}