2012-12-12 93 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"); 
    ^