BOOST_STATIC_ASSERT ohne Boost

Lesezeit: 5 Minuten

BOOST STATIC ASSERT ohne Boost
Konstantin

Da Boost in einem Unternehmen, für das ich arbeite, verboten ist, muss ich seine Funktionalität in reinem C++ implementieren. Ich habe mir Boost-Quellen angesehen, aber sie scheinen zumindest für mich zu komplex zu sein, um sie zu verstehen. Ich weiß, dass es etwas namens gibt static_assert() im C++0x-Standard, aber ich möchte keine C++0x-Features verwenden.

  • Hast du gefragt, warum du keinen Boost verwenden darfst?

    – Gregory Pakosz

    30. Dezember 2009 um 14:05 Uhr

  • Niemand hat sich die Mühe gemacht, den Fall so aufzubauen, dass das Anwaltsteam seine Zustimmung zu seiner Verwendung gibt?

    – Ein Programmierer

    30. Dezember 2009 um 14:24 Uhr

  • @Gregory Pakosz, sagen sie, weil es zu komplex ist 🙂

    – Konstantin

    30. Dezember 2009 um 22:26 Uhr

  • und können Sie eine Art Compiler verwenden? weil sie auch komplex sind

    – grauer Wolf

    27. Januar 16 um 16:33 Uhr

1642819805 338 BOOST STATIC ASSERT ohne Boost
Ein Programmierer

Ein weiterer Trick (der in C verwendet werden kann) besteht darin, zu versuchen, ein Array mit einer negativen Größe zu erstellen, wenn die Bestätigung fehlschlägt:

#define ASSERT(cond) int foo[(cond) ? 1 : -1]

Als Bonus können Sie anstelle eines Objekts ein Typedef verwenden, damit es in mehr Kontexten verwendet werden kann und nicht ausgeführt wird, wenn es erfolgreich ist:

#define ASSERT(cond) typedef int foo[(cond) ? 1 : -1]

Erstellen Sie schließlich einen Namen mit geringerer Wahrscheinlichkeit von Namenskonflikten (und zumindest in verschiedenen Zeilen wiederverwendbar):

#define CAT_(a, b) a ## b
#define CAT(a, b) CAT_(a, b)
#define ASSERT(cond) typedef int CAT(AsSeRt, __LINE__)[(cond) ? 1 : -1]

  • Könnte jemand erklären, warum zwei CAT-Makros notwendig sind? Welches Problem versuchst du zu vermeiden? Danke.

    – Grokus

    16. Dezember 10 um 20:24 Uhr

  • Wenn Sie das nicht tun, werden Argumente, die Makros sind (wie __LINE__) werden nicht erweitert. Es würde also generiert werden AsSeRt__LINE__ statt des Gesuchten AsSeRt42. Ich bin mir ziemlich sicher, dass es irgendwo eine Frage gibt, die dies im Detail erklärt.

    – Ein Programmierer

    17. Dezember 10 um 14:58 Uhr


BOOST STATIC ASSERT ohne Boost
Alexej Malistow

template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};

int main() {
   StaticAssert< (4>3) >(); //OK
   StaticAssert< (2+2==5) >(); //ERROR
}

  • +1 einfach genug, aber ich möchte, dass der Behauptung eine Nachricht zugeordnet ist

    – Gregory Pakosz

    30. Dezember 2009 um 14:07 Uhr

  • @Gregor: StaticAssert< (2+2==5) > associatedMessage();

    – Alexej Malistow

    30. Dezember 2009 um 17:19 Uhr

  • Es gibt jedoch Stellen, an denen Sie keine Variablen verwenden möchten / können

    – Gregory Pakosz

    30. Dezember 2009 um 19:34 Uhr

  • @Gregor: typedef StaticAssert< (2+2==5) > AssociatedMessage_t;

    – Alexej Malistow

    30. Dezember 2009 um 19:36 Uhr

  • Vermisst du nicht die struct Schlüsselwort in den ersten beiden Zeilen? Und das typedef Trick scheint nicht zu funktionieren – unvollständige Typen scheinen akzeptabel zu sein (tatsächlich scheint es, dass die Struktur sogar deklarieren könnte, z.

    – Onkel Bens

    31. Dezember 2009 um 10:49 Uhr

1642819805 472 BOOST STATIC ASSERT ohne Boost
Gregor Pakosz

Hier ist meine eigene Implementierung statischer Behauptungen, die aus meiner Codebasis extrahiert wurden: Pre-C++11 Static Assertions Without Boost.

Verwendung:

STATIC_ASSERT(expression, message);

Wenn der statische Assertionstest fehlschlägt, wird eine Compiler-Fehlermeldung angezeigt, die irgendwie die STATIC_ASSERTION_FAILED_AT_LINE_xxx_message generiert wird.

message muss ein gültiger C++ Bezeichner sein, wie z no_you_cant_have_a_pony was einen Compiler-Fehler erzeugt, der Folgendes enthält:

STATIC_ASSERTION_FAILED_AT_LINE_1337_no_you_cant_have_a_pony 🙂

#define CONCATENATE(arg1, arg2)   CONCATENATE1(arg1, arg2)
#define CONCATENATE1(arg1, arg2)  CONCATENATE2(arg1, arg2)
#define CONCATENATE2(arg1, arg2)  arg1##arg2

/**
 * Usage:
 *
 * <code>STATIC_ASSERT(expression, message)</code>
 *
 * When the static assertion test fails, a compiler error message that somehow
 * contains the "STATIC_ASSERTION_FAILED_AT_LINE_xxx_message" is generated.
 *
 * /! message has to be a valid C++ identifier, that is to say it must not
 * contain space characters, cannot start with a digit, etc.
 *
 * STATIC_ASSERT(true, this_message_will_never_be_displayed);
 */

#define STATIC_ASSERT(expression, message)
  struct CONCATENATE(__static_assertion_at_line_, __LINE__)
  {
    implementation::StaticAssertion<static_cast<bool>((expression))> CONCATENATE(CONCATENATE(CONCATENATE(STATIC_ASSERTION_FAILED_AT_LINE_, __LINE__), _), message);
  };
  typedef implementation::StaticAssertionTest<sizeof(CONCATENATE(__static_assertion_at_line_, __LINE__))> CONCATENATE(__static_assertion_test_at_line_, __LINE__)

  // note that we wrap the non existing type inside a struct to avoid warning
  // messages about unused variables when static assertions are used at function
  // scope
  // the use of sizeof makes sure the assertion error is not ignored by SFINAE

namespace implementation {

  template <bool>
  struct StaticAssertion;

  template <>
  struct StaticAssertion<true>
  {
  }; // StaticAssertion<true>

  template<int i>
  struct StaticAssertionTest
  {
  }; // StaticAssertionTest<int>

} // namespace implementation


STATIC_ASSERT(true, ok);
STATIC_ASSERT(false, ko);

int main()
{
  return 0;
}

  • Sehr schön! Dies ist eine vollständige Lösung (und eine gute Alternative zur Implementierung von Boost, wenn Sie Boost selbst vermeiden möchten) +1

    – Samaura

    9. März 13 um 20:40 Uhr


  • Wenn Sie haben -Wunused-local-typedef und Warnungen als Fehler, wird dies mit einem Fehler über unbenutzte Typedef fehlschlagen. Dies kann durch Hinzufügen umgangen werden __attribute__ ((unused)) zu der typedef in der STATIC_ASSERT Makro (zumindest für gcc und clang).

    – Jesper Matthiesen

    24. April 18 um 19:17 Uhr

Ich glaube das sollte funktionieren:

template<bool> struct CompileTimeAssert;   
template<> struct CompileTimeAssert<true>{};
#define STATIC_ASSERT(e) (CompileTimeAssert <(e) != 0>())

  • Ist das mit der Lizenz von Boost legal?

    – Gatopeich

    7. Juni 11 um 17:41 Uhr

Ich verwende die folgende Header-Datei, deren Code von jemand anderem kopiert wurde …

#ifndef STATIC_ASSERT__H
#define STATIC_ASSERT__H

/* ripped from http://www.pixelbeat.org/programming/gcc/static_assert.html */

#define ASSERT_CONCAT_(a, b) a##b
#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
/* These can't be used after statements in c89. */
#ifdef __COUNTER__
  /* microsoft */
  #define STATIC_ASSERT(e) enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1/(!!(e)) }
#else
  /* This can't be used twice on the same line so ensure if using in headers
   * that the headers are not included twice (by wrapping in #ifndef...#endif)
   * Note it doesn't cause an issue when used on same line of separate modules
   * compiled with gcc -combine -fwhole-program.  */
  #define STATIC_ASSERT(e) enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
#endif

/* http://msdn.microsoft.com/en-us/library/ms679289(VS.85).aspx */
#ifndef C_ASSERT
#define C_ASSERT(e) STATIC_ASSERT(e)
#endif

#endif

.

584230cookie-checkBOOST_STATIC_ASSERT ohne Boost

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy