Nach einigem Gräbt es wie mit std::initializer_list
aussieht, ist nicht möglich in GCC 4.7 aufgrund des Fehlen von constexpr
in seiner Erklärung. Es sollte arbeiten mit GCC 4.8 als <initializer_list>
wurde aktualisiert, um constexpr
enthalten. Leider ist die Verwendung von GCC 4.8 im Moment keine Option.
Es ist möglich, auf Elemente eines Arrays zuzugreifen, wenn der verfallene Zeiger durch Referenz übergeben wird. Dadurch kann die Validierung wie gewünscht durchgeführt werden, ist aber immer noch nicht die Lösung, auf die ich hoffe. Der folgende Code ist eine praktikable Lösung für Arrays. Es erfordert weiterhin, dass die Größe des Arrays an die Validierungsfunktion geliefert wird, dass es jedoch leicht genug ist, sie zu korrigieren.
#include <initializer_list>
template<typename T>
constexpr bool Compare(T& data, int size, int needleIndex, int haystackIndex)
{
return
needleIndex == haystackIndex ?
Compare(data, size, needleIndex + 1, haystackIndex)
: needleIndex == size ?
false
: data[needleIndex] == data[haystackIndex] ?
true
: Compare(data, size, needleIndex + 1, haystackIndex);
}
template<typename T>
constexpr bool Compare(T& data, int size, int index)
{
return
index == size ?
false
: Compare(data, size, index + 1) ?
true
: Compare(data, size, 0, index);
}
template<typename T, int ArraySize>
constexpr bool Validate(T(&input)[ArraySize], int size)
{
return !Compare(input, size, 0);
}
int main()
{
constexpr int initData0[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
constexpr int initData1[] = {1, 1, 2, 3, 4, 5, 6, 7, 8, 9};
constexpr int initData2[] = {2, 1, 2, 3, 4, 5, 6, 7, 8, 9};
constexpr int initData3[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 8};
constexpr int initData4[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 7};
constexpr int initData5[] = {0, 1, 0, 3, 4, 5, 6, 7, 8, 9};
constexpr int initData6[] = {0, 1, 2, 3, 4, 5, 6, 9, 8, 9};
static_assert(Validate(initData0, 10), "set 0 failed"); // <-- PASS
static_assert(Validate(initData1, 10), "set 1 failed"); // <-- (and below) FAIL
static_assert(Validate(initData2, 10), "set 2 failed");
static_assert(Validate(initData3, 10), "set 3 failed");
static_assert(Validate(initData4, 10), "set 4 failed");
static_assert(Validate(initData5, 10), "set 5 failed");
static_assert(Validate(initData6, 10), "set 6 failed");
}
.
Build-Log:
C:\Source\SwitchCaseString\main.cpp: In function 'int main()':
C:\Source\SwitchCaseString\main.cpp:198:2: error: static assertion failed: set 1 failed
C:\Source\SwitchCaseString\main.cpp:199:2: error: static assertion failed: set 2 failed
C:\Source\SwitchCaseString\main.cpp:200:2: error: static assertion failed: set 3 failed
C:\Source\SwitchCaseString\main.cpp:201:2: error: static assertion failed: set 4 failed
C:\Source\SwitchCaseString\main.cpp:202:2: error: static assertion failed: set 5 failed
C:\Source\SwitchCaseString\main.cpp:203:2: error: static assertion failed: set 6 failed
Nach dem derzeitigen Vorschlag für [C++ 14] (http://isocpp.org/files/papers/N3690.pdf), 'begin()' und ' end() 'von' std :: initializer_list' wird in Zukunft 'constexpr' sein (siehe 18.9/1). Das beseitigt ein Hindernis, aber ich bin nicht sicher, ob die Dereferenzierung der Iteratorwerte jemals zur Kompilierzeit möglich sein wird. – jogojapan
@jogojapan: Die "Iteratoren" einer 'std :: initializer_list' sind nur 'T *' - garantiert. –
Xeo
@Xeo Ja, und ich nahm an, dass die Dereferenzierung eines solchen Zeigers in einem konstanten Ausdruck nicht erlaubt wäre. – jogojapan