2017-09-19 7 views
0

J'ai besoin d'un moyen de valider qu'une chaîne constante ne contient pas un certain caractère au moment de la compilation. J'ai réfléchi à l'utilisation de static_assert, mais j'ai frappé un mur de briques parce que j'essayais d'utiliser la méthode .find, qui n'est pas constante.Des moyens créatifs de vérifier si une chaîne contient un caractère interdit à la compilation ou au moins avant son utilisation?

J'ai une option de faire la vérification dans le constructeur de la classe (les instances sont static const membres de ladite classe).
Mais avant de mordre la balle (puisque changer le comportement du constructeur a d'autres implications), j'aimerais voir si quelqu'un d'autre a une de ces idées créatives prêtes à l'emploi pour faire cela, de préférence au moment de la compilation .

+1

Vous pouvez utiliser la fonction constexpr de la chaîne C-littérale. Gcc a aussi une extension donc autorisez udl sur une chaîne littérale. – Jarod42

+0

Spot sur! J'ai réussi à le faire fonctionner. Bien que je pense @AndyG réponse ci-dessous est plus lisible (marquage comme réponse pour aider les autres), voici ce que j'ai réussi à faire avec votre suggestion: –

Répondre

4

Par chaîne constante peut-être vous dire un littéral chaîne , pour std::string ne peut pas être utilisé dans une expression constante.

Dans la chaîne cas littérale, nous pouvons tirer profit de constexpr: (Live Demo)

template<int N> 
constexpr bool has_forbidden_char(const char (&str) [N], char forbidden) 
{ 
    for(int i = 0; i < N; ++i) 
    { 
     if (str[i] == forbidden) 
      return true; 
    } 
    return false; 
} 

int main() 
{ 
    static_assert(!has_forbidden_char("foobar", 'x')); 
    static_assert(has_forbidden_char("foobar", 'f')); 
} 

Edit: itérer à N-1 si vous supposez que vous ne recevrez littéraux de chaîne et non pas des tableaux arbitraires de caractère . De cette façon, vous ne vérifierez pas le caractère NULL '\ 0' à chaque fois. (Tableaux de longueur nulle n'existent pas en C++, donc pas de soucis sur l'indexation à -1)

//... 
for(int i = 0; i < N-1; ++i){ //... 

Edit2: Puisque vous utilisez Visual Studio 2015, qui n'a pas constexpr détendue fonctionnalité, voici une solution conforme C++ 11 qui fonctionne:

namespace detail { 
    template<int N> 
    constexpr bool has_forbidden_char_help(const char(&str)[N], char forbidden, int index) 
    { 
     return (index < N && (str[index] == forbidden || has_forbidden_char_help(str, forbidden, index+1))); 
    } 
} // namespace detail 

template<int N> 
constexpr bool has_forbidden_char(const char (&str) [N], char forbidden) 
{ 
    return detail::has_forbidden_char_help(str, forbidden, 0); 
} 

int main() 
{ 
    static_assert(!has_forbidden_char("foobar", 'x'), "foobar doesn't have x, so this shouldn't fail..."); 
    static_assert(has_forbidden_char("foobar", 'f'), "foobar does have f, so this shouldn't fail..."); 
} 
+0

Merci pour l'exemple détaillé, @ AndyG. Malheureusement, mon compilateur (VS2015) n'a pas aimé la plupart des constructions que vous avez utilisées et le changement de compilateur n'est pas une option. –

+0

@SeeSharper: Donnez-moi une minute et je vais faire une version conforme VS2015. – AndyG

+0

@SeeSharper: Voir la réponse éditée :-) – AndyG