Poiché boost è vietato in un'azienda per cui lavoro, devo implementare la sua funzionalità in puro C++. Ho esaminato le fonti di spinta, ma sembrano essere troppo complesse per capire, almeno per me. So che c'è qualcosa chiamato static_assert()
nello standard di C++ 0x, ma mi piacerebbe non usare nessuna caratteristica di C++ 0x.BOOST_STATIC_ASSERT senza boost
risposta
template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};
int main() {
StaticAssert< (4>3) >(); //OK
StaticAssert< (2+2==5) >(); //ERROR
}
+1 abbastanza semplice, ma mi piace avere un messaggio associato all'asserzione –
@Gregory: 'StaticAssert associatedMessage();' –
ci sono luoghi in cui non vuoi/non puoi usare le variabili anche se –
Si potrebbe semplicemente copiare la macro dal Boost source file per il proprio codice. Se non hai bisogno di supportare tutti i compilatori Boost supporta puoi semplicemente scegliere la definizione giusta per il tuo compilatore e omettere il resto degli #ifdef
s in quel file.
È legale con la licenza di Boost? – gatopeich
Un altro trucco (che può essere utilizzato in C) è quello di cercare di costruire una matrice con una dimensione negativo se l'asserzione venga meno
#define ASSERT(cond) int foo[(cond) ? 1 : -1]
come bonus, si può utilizzare un typedef invece di un oggetto, in modo che sia utilizzabile in più contesti e non lo fa avviene quando si riesce:
#define ASSERT(cond) typedef int foo[(cond) ? 1 : -1]
infine, costruire un nome con meno possibilità di nome scontro (e riutilizzabili almeno in linee diverse):
#define CAT_(a, b) a ## b
#define CAT(a, b) CAT_(a, b)
#define ASSERT(cond) typedef int CAT(AsSeRt, __LINE__)[(cond) ? 1 : -1]
Qualcuno potrebbe spiegare perché sono necessarie due macro CAT? Che problema stai cercando di evitare? Grazie. – grokus
Se non lo fai, gli argomenti che sono macro (come '__LINE__') non sono espansi. Quindi genererebbe 'AsSeRt__LINE__' invece del desiderato' AsSeRt42'. Sono abbastanza sicuro che ci sia una domanda da qualche parte che spiega questo in dettaglio. – AProgrammer
Sto usando il seguente file di intestazione, con il codice di strappato da qualcun altro ...
#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
Qui è la mia propria implementazione di asserzioni statici estratte dalla mia base di codice: Pre-C++11 Static Assertions Without Boost
.
Usage:
STATIC_ASSERT(expression, message);
Quando il test di asserzione statica fallisce, viene generato un messaggio di errore del compilatore che contiene in qualche modo la STATIC_ASSERTION_FAILED_AT_LINE_xxx_message
.
message
deve essere un identificatore valido C++, come no_you_cant_have_a_pony
che produrrà un errore di compilazione contenente:
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;
}
+1 per "no_you_cant_have_a_pony" –
Molto bello! Questa è una soluzione completa (e una buona alternativa all'implementazione di boost se vuoi evitare l'auto-boost) +1 – Samaursa
Credo che questo dovrebbe funzionare:
template<bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true>{};
#define STATIC_ASSERT(e) (CompileTimeAssert <(e) != 0>())
fatto chiedi perché non ti è permesso usare boost? –
Nessuno si è preso la briga di costruire il caso in modo che la squadra dell'avvocato ne approvasse l'uso? – AProgrammer
@Gregory Pakosz, dicono perché è troppo complesso :) – Konstantin