2012-12-12 41 views
7

這裏是我想要做的顯示整數

enum First 
{ 
    a, 
    b, 
    c, 
    nbElementFirstEnum, 
}; 
enum Second 
{ 
    a, 
    b, 
    c, 
    nbElementSecondEnum, 
}; 

static_assert(
    First::nbElementFirstEnum == Second::nbElementSecondEnum, 
    "Not the same number of element in the enums."); 
/*static_assert( 
    First::nbElementFirstEnum == Second::nbElementSecondEnum, 
    "Not the same number of element in the enums." + First::nbElementFirstEnum + " " + Second::nbElementSecondEnum);*/ 

的簡化版本,但我希望能夠打印首先:: nbElementFirstEnum和二值::斷言消息中的nbElementSecondEnum(就像在註釋版本中顯然不起作用)。 我試過用「#」宏連接。 我也嘗試使用可變參數模板,用%10檢索每個數字並向檢索的值添加'0'字符,但我得到的只是一個constexpr char []。

所以我的問題是如何讓我的枚舉值打印在字符串文字中。

可能的重複:

C++11 static_assert: Parameterized error messages

Integrate type name in static_assert output?

最有趣的話題是這一個: Printing sizeof(T) at compile time 但我不希望有一個警告,或者decomment代碼知道值。

回答

4

這基本上可行,儘管可以稍微付出一些努力(通過使V1和V2總和爲256的倍數)。所以,我認爲你的解決方案很醜,但仍然更加強大。

template <int V1, int V2> struct AssertEquality 
{ 
    static const char not_equal_warning = V1 + V2 + 256; 
}; 

template <int V> struct AssertEquality<V, V> 
{ 
    static const bool not_equal_warning = 0; 
}; 

#define ASSERT_EQUALITY(V1, V2) static_assert(\ 
    AssertEquality<static_cast<int>(V1), \ 
        static_cast<int>(V2)>::not_equal_warning == 0, \ 
    #V1 " != " #V2); 

// ... 

ASSERT_EQUALITY(First::nbElementFirstEnum, Second::nbElementSecondEnum); 

與輸出看起來像:

g++ -std=c++0x -c chksz.cpp 
chksz.cpp: In instantiation of ‘const char AssertEquality<3, 2>::not_equal_warning’: 
chksz.cpp:40:124: instantiated from here 
chksz.cpp:5:53: warning: overflow in implicit constant conversion 
chksz.cpp:40:1: error: static assertion failed: "First::nbElementFirstEnum != Second::nbElementSecondEnum" 

以供參考,這最初的版本取決於GCC打印static_assert消息即使在布爾條件不編譯的。

template <typename Enum1, int Max1, typename Enum2, int Max2> 
struct AssertSameSizeEnums; 

template <typename Enum1, int EnumMax, typename Enum2> 
struct AssertSameSizeEnums<Enum1, EnumMax, Enum2, EnumMax> {}; 
// only define the special case where Max1 and Max2 have the same integer value 

#define ASSERT_SAME_SIZE_ENUMS(E1, M1, E2, M2) static_assert(\ 
    sizeof(AssertSameSizeEnums<E1, E1::M1, E2, E2::M2>), \ 
    #E1 "::" #M1 " != " #E2 "::" #M2); 

enum class First { 
    a, b, c, nbElementFirstEnum, 
}; 
enum class Second { 
    a, b, c, nbElementSecondEnum, 
}; 

ASSERT_SAME_SIZE_ENUMS(First, nbElementFirstEnum, Second, nbElementSecondEnum); 

注意我改變了你的枚舉是強類型的,因爲否則枚舉常量名發生衝突。如果你有弱類型的枚舉,傳遞給宏的FirstSecond應該命名爲封閉範圍。

現在,如果我註釋掉值(所以枚舉的大小不同)之一,我得到:

g++ -std=c++0x -c chksz.cpp 
chksz.cpp:25:113: error: invalid application of ‘sizeof’ to incomplete type ‘AssertSameSizeEnums<First, 3, Second, 2>’ 
chksz.cpp:25:1: error: static assertion failed: "First::nbElementFirstEnum != Second::nbElementSecondEnum" 

看到整數值的顯示方式不完全類型錯誤時,符號名在靜態斷言中?

+0

(我用gcc 4.7)這很奇怪,因爲你不能一個強類型枚舉轉換成一個整數自動你必須使用static_cast,但gcc停在「不完整類型」的錯誤,並不會顯示static_assert錯誤我ssage。 – b3nj1

+0

好吧,我只是在舊版本(4.5.1)上快速測試過。如果你改變宏使用'static_cast (E1 :: M1)'等,那麼這是如何工作的? – Useless

+0

其實我們並不需要顯示枚舉的名稱,只有值。問題更多的是gcc在「不完整類型」錯誤處停止,並且不顯示static_assert錯誤消息。我們觸發了一個警告,以便引發static_assert。 – b3nj1

1

下面是我找到的解決方案,我們收到一條帶有值和static_assert錯誤消息的警告消息。

template<int N> 
struct TriggerOverflowWarning 
{ 
    static constexpr char value() { return N + 256; } 
}; 

template <int N, int M, typename Enable = void> 
struct CheckEqualityWithWarning 
{ 
    static constexpr bool value = true; 
}; 

template <int N, int M> 
struct CheckEqualityWithWarning<N, M, typename std::enable_if<N != M>::type> 
{ 
    static constexpr bool value = (TriggerOverflowWarning<N>::value() == TriggerOverflowWarning<M>::value()); 
}; 

static constexpr int a = 9; 
static constexpr int b = 10; 

static_assert(CheckEqualityWithWarning<a, b>::value, "Mismatch."); 

這裏是gcc的輸出:

g++ -std=c++11 -c test.cpp 
test.cpp: In instantiation of 'static constexpr char TriggerOverflowWarning<N>::value() [with int N = 10]': 
test.cpp:18:112: required from 'constexpr const bool CheckEqualityWithWarning<9, 10>::value' 
test.cpp:24:51: required from here 
test.cpp:6:52: warning: overflow in implicit constant conversion [-Woverflow] 
test.cpp: In instantiation of 'static constexpr char TriggerOverflowWarning<N>::value() [with int N = 9]': 
test.cpp:18:112: required from 'constexpr const bool CheckEqualityWithWarning<9, 10>::value' 
test.cpp:24:51: required from here 
test.cpp:6:52: warning: overflow in implicit constant conversion [-Woverflow] 
test.cpp:24:5: error: static assertion failed: Mismatch. 

正是基於此解決方案:Printing sizeof(T) at compile time

+0

即使使用'static_assert'輸出,我也不確定這是否是更清潔的或比我更可讀(老實說,它看起來很嘈雜)。但是,這是你的問題和你的要求。 – Useless

+0

我不得不同意它很嘈雜,但我需要錯誤信息和要打印的值......現在這是最好的我必須這樣做(我知道這是有點醜陋,但我打開任何其他解決方案:)。您的解決方案非常聰明,但不會顯示錯誤消息:/您使用的是哪個版本的gcc? (順便說一句,我建議你添加static_casts到你的解決方案)。 – b3nj1

+0

正如我所說的,我正在使用4.5.1 ...打印消息,即使布爾條件無法編譯也可能是一個錯誤。 – Useless

0

與上面的問題是,他們依靠這可能會或可能不存在的警告不同的編譯器,並且可能不會每個人都打開。 (實際上,其中一個打開所有警告時不顯示Clang的值。)

根據C++標準,此解決方案從此處的其他解決方案中吸取了教訓,但利用了類型系統,因此始終是一個實際的錯誤。不幸的是,這確實會提前停止,並且不會自己觸發static_assert錯誤,這是一個缺點。這已經在GCC 5.3和Clang 3.7上進行了測試,沒有發出任何警告。

template <long V1, long V2> 
struct StaticAssertEquality 
{ 
    static constexpr void* NotEqualError() { return V1 + V2; } 
}; 

template <long V> 
struct StaticAssertEquality<V, V> 
{ 
    static constexpr bool NotEqualError = true; 
}; 

#define STATIC_ASSERT_LONG_EQUALITY(V1, V2)       \ 
    static_assert(             \ 
    StaticAssertEquality<static_cast<long>(V1),      \ 
         static_cast<long>(V2)>::NotEqualError,  \ 
    #V1 " != " #V2) 

// ... 

STATIC_ASSERT_LONG_EQUALITY(1, 2); 

它顯然不適用於全部無符號長整數。作爲一個額外的安全措施,宏可以包括第二個簡單的static_assert(V1 == V2, #V1 " != " #V2);來捕捉類型轉換中的任何雜散意外的平等。

輸出看起來像這樣爲鏘:

file.cpp: error: cannot initialize return object of type 'void *' with an rvalue of type 'long' 
    static constexpr void* NotEqualError() { return V1 + V2; } 
                ^~~~~~~ 
file.cpp: note: in instantiation of member function 'StaticAssertEquality<1, 2>::NotEqualError' requested here 
    STATIC_ASSERT_LONG_EQUALITY(1, 2); 
^
file.cpp: note: expanded from macro 'STATIC_ASSERT_LONG_EQUALITY' 
           static_cast<long>(V2)>::NotEqualError,  \ 
                ^
1 error generated. 

輸出與GCC:

file.cpp: In instantiation of 'static constexpr void* StaticAssertEquality<V1, V2>::NotEqualError() [with long V1 = 1; long V2 = 2]': 
file.cpp: required from here 
file.cpp: error: invalid conversion from 'long' to 'void*' [-fpermissive] 
    static constexpr void* NotEqualError() { return V1 + V2; } 
                 ^
g++.exe: failed with exit code 1 (00000001) 
+0

事實上,static_assert失敗信息現在幾乎沒有問題,因爲你從來沒有看到它.... –

1

首先一個輔助類的編譯器輸出打印模板參數值:

template<size_t A, size_t B> struct TAssertEquality { 
    static_assert(A==B, "Not equal"); 
    static constexpr bool _cResult = (A==B); 
}; 

那麼你需要測試它:

static constexpr bool _cIsEqual = 
    TAssertEquality<First::nbElementFirstEnum, Second::nbElementSecondEnum>::_cResult; 

的編譯器錯誤消息看起來像:

注:見參考文獻類模板實例 'TAssertEquality < 32,64>' 正在編制

0

隨着C++11decltype

#define UTILITY_PP_STRINGIZE_(x) #x 
#define UTILITY_PP_STRINGIZE(x) UTILITY_PP_STRINGIZE_(x) 

#define STATIC_ASSERT_TRUE(exp, msg) static_assert(::utility::StaticAssertTrue<decltype(exp), (exp)>::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 
#define STATIC_ASSERT_TRUE1(exp, v1, msg) \ 
    static_assert(::utility::StaticAssertTrue<decltype(exp), (exp), \ 
        ::utility::StaticAssertParam<decltype(v1), (v1)> >::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 
#define STATIC_ASSERT_TRUE2(exp, v1, v2, msg) \ 
    static_assert(::utility::StaticAssertTrue<decltype(exp), (exp), \ 
        ::utility::StaticAssertParam<decltype(v1), (v1)>, \ 
        ::utility::StaticAssertParam<decltype(v2), (v2)> >::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 
#define STATIC_ASSERT_TRUE3(exp, v1, v2, v3, msg) \ 
    static_assert(::utility::StaticAssertTrue<decltype(exp), (exp), \ 
        ::utility::StaticAssertParam<decltype(v1), (v1)>, \ 
        ::utility::StaticAssertParam<decltype(v2), (v2)>, \ 
        ::utility::StaticAssertParam<decltype(v3), (v3)> >::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 
#define STATIC_ASSERT_TRUE4(exp, v1, v2, v3, v4, msg) \ 
    static_assert(::utility::StaticAssertTrue<decltype(exp), (exp), \ 
        ::utility::StaticAssertParam<decltype(v1), (v1)>, \ 
        ::utility::StaticAssertParam<decltype(v2), (v2)>, \ 
        ::utility::StaticAssertParam<decltype(v3), (v3)>, \ 
        ::utility::StaticAssertParam<decltype(v4), (v4)> >::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 

#define STATIC_ASSERT_FALSE(exp, msg) static_assert(::utility::StaticAssertFalse<decltype(exp), (exp)>::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 
#define STATIC_ASSERT_FALSE1(exp, v1, msg) \ 
    static_assert(::utility::StaticAssertFalse<decltype(exp), (exp), \ 
        ::utility::StaticAssertParam<decltype(v1), (v1)> >::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 
#define STATIC_ASSERT_FALSE2(exp, v1, v2, msg) \ 
    static_assert(::utility::StaticAssertFalse<decltype(exp), (exp), \ 
        ::utility::StaticAssertParam<decltype(v1), (v1)>, \ 
        ::utility::StaticAssertParam<decltype(v2), (v2)> >::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 
#define STATIC_ASSERT_FALSE3(exp, v1, v2, v3, msg) \ 
    static_assert(::utility::StaticAssertFalse<decltype(exp), (exp), \ 
        ::utility::StaticAssertParam<decltype(v1), (v1)>, \ 
        ::utility::StaticAssertParam<decltype(v2), (v2)>, \ 
        ::utility::StaticAssertParam<decltype(v3), (v3)> >::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 
#define STATIC_ASSERT_FALSE4(exp, v1, v2, v3, v4, msg) \ 
    static_assert(::utility::StaticAssertFalse<decltype(exp), (exp), \ 
        ::utility::StaticAssertParam<decltype(v1), (v1)>, \ 
        ::utility::StaticAssertParam<decltype(v2), (v2)>, \ 
        ::utility::StaticAssertParam<decltype(v3), (v3)>, \ 
        ::utility::StaticAssertParam<decltype(v4), (v4)> >::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 

#define STATIC_ASSERT_EQ(v1, v2, msg) static_assert(::utility::StaticAssertEQ<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: \"" UTILITY_PP_STRINGIZE(v1) " == " UTILITY_PP_STRINGIZE(v2) "\": " msg) 
#define STATIC_ASSERT_NE(v1, v2, msg) static_assert(::utility::StaticAssertNE<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: \"" UTILITY_PP_STRINGIZE(v1) " != " UTILITY_PP_STRINGIZE(v2) "\": " msg) 
#define STATIC_ASSERT_LE(v1, v2, msg) static_assert(::utility::StaticAssertLE<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: \"" UTILITY_PP_STRINGIZE(v1) " <= " UTILITY_PP_STRINGIZE(v2) "\": " msg) 
#define STATIC_ASSERT_LT(v1, v2, msg) static_assert(::utility::StaticAssertLT<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: \"" UTILITY_PP_STRINGIZE(v1) " < " UTILITY_PP_STRINGIZE(v2) "\": " msg) 
#define STATIC_ASSERT_GE(v1, v2, msg) static_assert(::utility::StaticAssertGE<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: \"" UTILITY_PP_STRINGIZE(v1) " >= " UTILITY_PP_STRINGIZE(v2) "\": " msg) 
#define STATIC_ASSERT_GT(v1, v2, msg) static_assert(::utility::StaticAssertGT<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: \"" UTILITY_PP_STRINGIZE(v1) " > " UTILITY_PP_STRINGIZE(v2) "\": " msg) 


namespace utility 
{ 
    template <typename T, T v> 
    struct StaticAssertParam 
    { 
    }; 

    template <typename T, T v, typename ...Params> 
    struct StaticAssertTrue; 

    template <typename T, T v> 
    struct StaticAssertTrue<T, v> 
    { 
     static const bool value = (v ? true : false); 
    }; 

    template <typename T, T v, typename ...Params> 
    struct StaticAssertTrue 
    { 
     static const bool value = (v ? true : false); 
     static_assert(v ? true : false, "StaticAssertTrue with parameters failed."); 
    }; 

    template <typename T, T v, typename ...Params> 
    struct StaticAssertFalse; 

    template <typename T, T v> 
    struct StaticAssertFalse<T, v> 
    { 
     static const bool value = (v ? false : true); 
    }; 

    template <typename T, T v, typename ...Params> 
    struct StaticAssertFalse 
    { 
     static const bool value = (v ? false : true); 
     static_assert(v ? false : true, "StaticAssertFalse with parameters failed."); 
    }; 

    template <typename U, typename V, U u, V v> 
    struct StaticAssertEQ 
    { 
     static const bool value = (u == v); 
     static_assert(u == v, "StaticAssertEQ failed."); 
    }; 

    template <typename U, typename V, U u, V v> 
    struct StaticAssertNE 
    { 
     static const bool value = (u != v); 
     static_assert(u != v, "StaticAssertNE failed."); 
    }; 

    template <typename U, typename V, U u, V v> 
    struct StaticAssertLE 
    { 
     static const bool value = (u <= v); 
     static_assert(u <= v, "StaticAssertLE failed."); 
    }; 

    template <typename U, typename V, U u, V v> 
    struct StaticAssertLT 
    { 
     static const bool value = (u < v); 
     static_assert(u < v, "StaticAssertLT failed."); 
    }; 

    template <typename U, typename V, U u, V v> 
    struct StaticAssertGE 
    { 
     static const bool value = (u >= v); 
     static_assert(u >= v, "StaticAssertGE failed."); 
    }; 

    template <typename U, typename V, U u, V v> 
    struct StaticAssertGT 
    { 
     static const bool value = (u > v); 
     static_assert(u > v, "StaticAssertGT failed."); 
    }; 
} 

用法:

struct A 
{ 
    int a[4]; 
}; 

#define Float1 1.1f 
#define Float2 1.2f 

int main() 
{ 
    static const int a = 3; 
    static const long b = 5; 
    static const long c = 7; 
    static const long d = 9; 
    STATIC_ASSERT_TRUE4(a == b && c == d, a, b, c, d, "long_expression_with_multiple_integral_variables"); 

    #pragma message("----------------------------------------") 

    STATIC_ASSERT_TRUE(Float1 == Float2, "expression_with_floats"); 

    #pragma message("----------------------------------------") 

    STATIC_ASSERT_EQ(10, sizeof(A), "simple_integral_expression_1"); 

    #pragma message("----------------------------------------") 

    STATIC_ASSERT_EQ(11, sizeof(A), "simple_integral_expression_2"); 
    return 0; 
} 

MSVC2017:

source_file.cpp(72): error C2338: StaticAssertTrue with parameters failed. 
source_file.cpp(148): note: see reference to class template instantiation 'utility::StaticAssertTrue<bool,false,utility::StaticAssertParam<const int,3>,utility::StaticAssertParam<const long,5>,utility::StaticAssertParam<const long,7>,utility::StaticAssertParam<const long,9>>' being compiled 
source_file.cpp(148): error C2338: expression: "a == b && c == d": long_expression_with_multiple_integral_variables 
---------------------------------------- 
source_file.cpp(152): error C2338: expression: "1.1f == 1.2f": expression_with_floats 
---------------------------------------- 
source_file.cpp(95): error C2338: StaticAssertEQ failed. 
source_file.cpp(156): note: see reference to class template instantiation 'utility::StaticAssertEQ<int,size_t,10,16>' being compiled 
source_file.cpp(156): error C2338: expression: "10 == sizeof(A)": simple_integral_expression_1 
---------------------------------------- 
source_file.cpp(160): error C2338: expression: "11 == sizeof(A)": simple_integral_expression_2 

GCC 4.8.x:

<source>: In instantiation of 'struct utility::StaticAssertTrue<bool, false, utility::StaticAssertParam<const int, 3>, utility::StaticAssertParam<const long int, 5l>, utility::StaticAssertParam<const long int, 7l>, utility::StaticAssertParam<const long int, 9l> >': 
<source>:148:5: required from here 
<source>:72:9: error: static assertion failed: StaticAssertTrue with parameters failed. 
     static_assert(v ? true : false, "StaticAssertTrue with parameters failed."); 
     ^
<source>: In function 'int main()': 
<source>:18:5: error: static assertion failed: expression: "a == b && c == d": long_expression_with_multiple_integral_variables 
    static_assert(::utility::StaticAssertTrue<decltype(exp), (exp), \ 
    ^
<source>:148:5: note: in expansion of macro 'STATIC_ASSERT_TRUE4' 
    STATIC_ASSERT_TRUE4(a == b && c == d, a, b, c, d, "long_expression_with_multiple_integral_variables"); 
    ^
<source>:150:63: note: #pragma message: ---------------------------------------- 
    #pragma message("----------------------------------------") 
                  ^
<source>:4:41: error: static assertion failed: expression: "1.1f == 1.2f": expression_with_floats 
#define STATIC_ASSERT_TRUE(exp, msg) static_assert(::utility::StaticAssertTrue<decltype(exp), (exp)>::value, "expression: \"" UTILITY_PP_STRINGIZE(exp) "\": " msg) 
             ^
<source>:152:5: note: in expansion of macro 'STATIC_ASSERT_TRUE' 
    STATIC_ASSERT_TRUE(Float1 == Float2, "expression_with_floats"); 
    ^
<source>:154:63: note: #pragma message: ---------------------------------------- 
    #pragma message("----------------------------------------") 
                  ^
<source>: In instantiation of 'struct utility::StaticAssertEQ<int, long unsigned int, 10, 16ul>': 
<source>:156:5: required from here 
<source>:95:9: error: static assertion failed: StaticAssertEQ failed. 
     static_assert(u == v, "StaticAssertEQ failed."); 
     ^
<source>:44:41: error: static assertion failed: expression: "10 == sizeof(A)": simple_integral_expression_1 
#define STATIC_ASSERT_EQ(v1, v2, msg) static_assert(::utility::StaticAssertEQ<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: \"" UTILITY_PP_STRINGIZE(v1) " == " UTILITY_PP_STRINGIZE(v2) "\": " msg) 
             ^
<source>:156:5: note: in expansion of macro 'STATIC_ASSERT_EQ' 
    STATIC_ASSERT_EQ(10, sizeof(A), "simple_integral_expression_1"); 
    ^
<source>:158:63: note: #pragma message: ---------------------------------------- 
    #pragma message("----------------------------------------") 
                  ^
<source>: In instantiation of 'struct utility::StaticAssertEQ<int, long unsigned int, 11, 16ul>': 
<source>:160:5: required from here 
<source>:95:9: error: static assertion failed: StaticAssertEQ failed. 
     static_assert(u == v, "StaticAssertEQ failed."); 
     ^
<source>:44:41: error: static assertion failed: expression: "11 == sizeof(A)": simple_integral_expression_2 
#define STATIC_ASSERT_EQ(v1, v2, msg) static_assert(::utility::StaticAssertEQ<decltype(v1), decltype(v2), (v1), (v2)>::value, "expression: \"" UTILITY_PP_STRINGIZE(v1) " == " UTILITY_PP_STRINGIZE(v2) "\": " msg) 
             ^
<source>:160:5: note: in expansion of macro 'STATIC_ASSERT_EQ' 
    STATIC_ASSERT_EQ(11, sizeof(A), "simple_integral_expression_2"); 
    ^