2014-12-15 32 views
8

Chciałbym utworzyć makro, które może porównać 2 ciągi i wygenerować błąd czasu kompilacji, jeśli warunek nie zostanie spełniony. Może to być jednak twierdzenie o czasie kompilacji.W jaki sposób można statycznie porównywać dwa ciągi znaków w czasie kompilacji?

Nie jestem pewien, jak mógłbym to zrobić.

Na przykład:

STATIC_COMPARE("THIS STRING","THIS STRING") -> would emit a compile time error 
STATIC_COMPARE("THIS STRING","THIS OTHER STRING) -> wouldn't emit a compile time error. 

Makro wyglądałyby

#define STATIC_COMPARE(str1,str2) if (str1==str2) emit an error with a message 

Sądzę więc, że kwestia sprowadza się do bycia w stanie porównać 2 ciągi w czasie kompilacji.

+0

Czy zakładając ciąg dosłownego łączenie również powiązane z [długość obliczeniowa ciąg C w czasie kompilacji. Czy to naprawdę jest constexpr?] (Http://stackoverflow.com/q/25890784/1708801) –

Odpowiedz

8

Można to z C++ 11 zrobić za pomocą constexpr funkcję:

constexpr bool strings_equal(char const * a, char const * b) { 
    return *a == *b && (*a == '\0' || strings_equal(a + 1, b + 1)); 
} 

(See a demo)

To nie jest możliwe, aby to zrobić przed C++ 11, z zastrzeżeniem, że wiele kompilatorów będzie kompilować równe ciągi literałów jako wskaźnik do tej samej lokalizacji. W przypadku tych kompilatorów wystarczy porównać ciągi bezpośrednio, ponieważ oba będą oceniane jako równe wskaźniki.

+0

@cdhowie To dość nietrywialne, ale w porządku. – Columbo

+0

, który korzystał z coliru na tej samej stronie. wypróbowałem to na clang z 1y, działa dobrze. usunie mój komentarz. –

+0

Próbuję uruchomić to w Xcode - nie mogłem. Być może istnieje inny sposób, aby stworzyć statyczne potwierdzenie w tym środowisku. Znalazłem kilka zasobów, ale nie udało mi się go uruchomić. http://en.cppreference.com/w/cpp/language/static_assert –

-1

Nie sądzę, że możliwe jest porównanie dwóch literałów ciągu w czasie kompilacji z makrem.

Dokonanie makr do normalnej pętli for, która porównuje łańcuchy, zostanie prawdopodobnie zoptymalizowane do postaci stałej przez dobry kompilator, jeśli dwa ciągi są stałymi.

Od C++ 11 można to zrobić za pomocą funkcji constexpr zamiast makra. Ponieważ C++ 14 constexpr może zawierać pętlę, w C++ 11 musi to być w zasadzie pojedyncza instrukcja return <expression>. Ale można to zrobić za pomocą wyrażenia rekursywnego, jak w poniższej odpowiedzi.

+3

Z szacunkiem - wierzę, że inne odpowiedzi dostarczają tej informacji wprost i bardziej szczegółowo; zasugeruj, że rozważasz usunięcie swojej odpowiedzi. – einpoklum

3

Można użyć funkcji constexpr. Oto sposób C++ 14:

constexpr bool equal(char const* lhs, char const* rhs) 
{ 
    while (*lhs || *rhs) 
     if (*lhs++ != *rhs++) 
      return false; 
    return true; 
} 

Demo.

1

Można to zrobić w C++ 11 przy użyciu constexpr. Definiując funkcję rekursywną, możesz sprawdzić, czy ciąg znaków jest równy, czy nie.

constexpr bool isequal(char const *one, char const *two) 
{ 
    return (*one && *two) ? (*one == *two && isequal(one + 1, two + 1)) : (!*one && !*two); 
} 

static_assert(isequal("foo", "foo"), "this should never fail"); 
static_assert(!isequal("foo", "bar"), "this should never fail"); 

Ten kod użyłem dzięki Johannes Schaub i widać pełny, więc zakładać here