Typsicheres count_of( array ) Makro
-
Es wurde ja schon desöfteren darüber diskutiert, wie man die Größe eines Array zur Compilezeit herausfinden kann, dass dies aber bei Pointern falsche Werte liefert und dass man dies über ein Template abfangen könnte, das Ergebnis (vor constexpr in C++0x) dann aber nicht mehr compilezeit-konstant wäre.
Zur Erinnerung:
#define count_of( array ) (sizeof(array) / sizeof(*array)) // liefert bei Zeigern falsche Werte template< typename T, size_t N > size_t count_of( T ( &array )[N] ) { return N; } // nicht konstant template< typename T, size_t N > constexpr size_t count_of( T ( &array )[N] ) { return N; } // erst ab C++0xIch versuche gerade, das ganze irgendwie typsicher und konstant zu bekommen. Mein bisheriger Ansatz geht zwar IMHO in die richtige Richtung, der "assertion helper" verhindert aber noch, das ganze in constant expressions zu verwenden. Sieht jemand einen Weg, den ich bisher übersehe? Oder gibt es einfach keine Möglichkeit?
namespace detail { template< typename T, size_t N > void countof_assert( T ( &array )[ N ] ) { } } // namespace detail #define countof( array ) ( detail::countof_assert( array ), sizeof( array ) / sizeof( *array ) ) // Bei Aufruf mit allem, was kein Array ist, wirft der Compiler eine "no candidates for call to countof_assert( ... )" Meldung
-
für genau die Problematik wurde std::tr1::array geschaffen (oder boost::array)
-
Manchmal bekommt man aber nunmal ein nacktes Array einfach so vorgesetzt.
-
(ungetestet)
namespace detail { template<bool b, std::size_t size> struct count_of_impl; template<std::size_t size> struct count_of_impl<true, size> { static const std::size_t value = size; } } #define count_of(array) detail::count_of_impl<boost::is_array<BOOST_TYPEOF(array)>::value, sizeof(array)/sizeof(*array)>::value
-
namespace detail { template< typename T, size_t N > int countof_assert( T ( &array )[ N ] ); } // namespace detail #define countof( array ) ( (void)sizeof(detail::countof_assert( array )), sizeof( array ) / sizeof( *array ) )
-
Probiers mal so:
namespace detail { template< typename T, size_t N > T (&countof_assert(T(&array)[N]))[N] { return array; } } // namespace detail #define countof(array) ( sizeof(detail::countof_assert(array)) / sizeof(*array))
-
jokester schrieb:
Probiers mal so:
namespace detail { template< typename T, size_t N > T (&countof_assert(T(&array)[N]))[N]; { return array; } } // namespace detail #define countof(array) ( sizeof(detail::countof_assert(array)) / sizeof(*array))
namespace detail { template< typename T, size_t N > char (&countof_assert(T(&array)[N]))[N]; } // namespace detail #define countof(array) ( sizeof(detail::countof_assert(array)))
-
LordJaxom schrieb:
Manchmal bekommt man aber nunmal ein nacktes Array einfach so vorgesetzt.
Dann kriegt man es entweder als Pointer + Größenangabe geliefert, so dass die Größe zur Compilezeit nicht zu ermitteln ist.
Wie auch immer, folgendes ließ sich zumindest auf codepad und MSVC compilieren und liefert das richtige ergebnis:
template <class T> struct count_array; template <class T, size_t N> struct count_array<T [N]> { char c[N]; }; template <class T> count_array<T> count_(T&); #define count_of(X) sizeof(count_(X))Gilt allerdings nur, wenn sizeof beim struct == sizeof char[n]
-
pumuckl schrieb:
Dann kriegt man es entweder als Pointer + Größenangabe geliefert, so dass die Größe zur Compilezeit nicht zu ermitteln ist.
Immer diese Grundsatzdiskussionen

Also gut, im konkreten Fall haben wir viele Strukturen, die COBOL-Datenfelder abbilden. Diese enthalten nur Char-Arrays, Arrays von Char-Arrays oder Arrays von Strukturen, die selbiges enthalten. Da kommt der Bedarf halt ab und zu mal hoch.
Ansonsten danke für die Lösungen, der sizeof-Trick ist genial

-
volkard schrieb:
namespace detail { template< typename T, size_t N > char (&countof_assert(T(&array)[N]))[N]; } // namespace detail #define countof(array) ( sizeof(detail::countof_assert(array)))me like it

-
LordJaxom schrieb:
Ansonsten danke für die Lösungen, der sizeof-Trick ist genial

sizeofist sowieso genial. Man kann damit die verrücktesten Dinge tun, zum Beispiel Vererbungshierarchien zur Kompilierzeit zu erkennen...
-
Jo, allgemein finde ich den Trick
sizeof(OverloadedFunction(something))ziemlich cool.
-
Jetzt fällt mir endlich wieder ein wo es beim Template-Trick hakt: der erfordert dass T ein Typ mit "external linkage" ist.
Also sowas geht damit z.B. nicht:void foo() { struct bar { ... }; bar b[123]; countof(b); // bar hat keine "external linkage" -> fehler }Was auch der Grund ist warum ich das in unserer Basis-Library jetzt doch nicht umgeschrieben habe

-
Das kommt in unserem Anwendungsfall zum Glück nicht vor...