【问题标题】:Display integer at compile time in static_assert()在 static_assert() 编译时显示整数
【发布时间】:2012-11-30 00:48:35
【问题描述】:

这是我正在尝试做的简化版本

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);*/

但我希望能够在断言消息中打印 First::nbElementFirstEnum 和 Second::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 但我不想通过警告或注释代码来了解这些值。

【问题讨论】:

    标签: c++ macros c++11 integer static-assert


    【解决方案1】:

    这基本上是可行的,尽管可以通过一些努力来打破(通过使 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"
    

    看看整数值如何在不完整类型错误中显示,以及在静态断言中的符号名称?

    【讨论】:

    • (我使用的是 gcc 4.7)这很奇怪,因为您无法自动将强类型枚举转换为整数,您必须使用 static_cast,但 gcc 会在“不完整类型”错误处停止并且不会t 显示 static_assert 错误消息。
    • 好的,我刚刚在旧版本(4.5.1)上快速测试。如果您将宏更改为使用static_cast&lt;int&gt;(E1::M1) 等,它是如何工作的?
    • 其实我们并不需要显示枚举的名称,只需要显示值。问题更多的是 gcc 在“不完整类型”错误处停止并且不显示 static_assert 错误消息。我们成功触发了警告,从而引发了 static_assert。
    • 但是不完整的类型错误显示的是枚举值,对吧?
    • 是的,它们会显示,但不会显示错误消息:/ 我将发布一个可能的解决方案。
    【解决方案2】:

    首先在编译器输出中打印模板参数值的辅助类:

    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' 的参考

    【讨论】:

    • 将其更改为以下,以避免在 '_cIsEqual' 上出现未使用的变量警告。 (void) TAssertEquality<:nbelementfirstenum second::nbelementsecondenum>::_cResult;
    【解决方案3】:

    这是我找到的解决方案,我们收到一条警告消息,其中包含值和 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

    【讨论】:

    • 即使使用static_assert 输出,我也不确定它是否比我的更清晰或更易读(老实说,它看起来很吵)。但是,这是您的问题和您的要求。
    • 我不得不同意它很吵,但我需要错误消息和要打印的值......现在这是我必须这样做的最好的(我知道它有点难看,但我愿意接受任何其他解决方案:)。您的解决方案既聪明又好,但未打印错误消息:/您使用哪个版本的 gcc? (顺便说一句,我建议您将 static_casts 添加到您的解决方案中)。
    • 正如我所说,我使用的是 4.5.1 ...即使在布尔条件无法编译的情况下打印消息也可能是一个错误。
    • 此解决方案需要 -Wconversion 标志才能使 clang 正常工作。
    【解决方案4】:

    使用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");
         ^
    

    【讨论】:

      【解决方案5】:

      上面的问题是它们依赖于不同编译器上可能存在或不存在的警告,并且可能不是每个人都一直打开。 (事实上​​,其中一个在打开所有警告的情况下不会显示 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);
      

      显然,它不适用于 unsigned long 的全部范围。作为一个额外的安全措施,宏可以包含第二个简单的static_assert(V1 == V2, #V1 " != " #V2); 来捕捉类型转换中任何杂散的意外相等。

      Clang 的输出如下所示:

      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)
      

      【讨论】:

      • 事实上,static_assert 失败消息现在几乎不重要了,因为你永远看不到它......
      【解决方案6】:

      C++11 的另一种方法只是查找深度嵌套的类型或编译时间值。

      #include <vector>
      
      // generates compilation error and shows real type name (and place of declaration in some cases) in an error message, useful for debugging boost::mpl like recurrent types
      #define UTILITY_TYPE_LOOKUP_BY_ERROR(type_name) \
          using _type_lookup_t = decltype((*(typename ::utility::type_lookup<type_name >::type*)0).operator ,(*(::utility::dummy*)0))
      
      // lookup compile time template typename value
      #define UTILITY_PARAM_LOOKUP_BY_ERROR(static_param) \
          UTILITY_TYPE_LOOKUP_BY_ERROR(STATIC_ASSERT_PARAM(static_param))
      
      #define STATIC_ASSERT_PARAM(v1) ::utility::StaticAssertParam<decltype(v1), (v1)>
      
      namespace utility
      {
          template <typename T>
          struct type_lookup
          {
              using type = T;
          };
      
          struct dummy {};
      
          template <typename T, T v>
          struct StaticAssertParam
          {
          };
      }
      
      struct test
      {
          char a[123];
          double b[15];
          std::vector<int> c;
      };
      
      UTILITY_PARAM_LOOKUP_BY_ERROR(sizeof(test));
      

      MSVC2017

      error C2039: ',': is not a member of 'utility::StaticAssertParam<size_t,272>'
      

      GCC 4.8.x:

      <source>:5 : 103 : error : 'using type = struct utility::StaticAssertParam<long unsigned int, 272ul>' has no member named 'operator,'
      using _type_lookup_t = decltype((*(typename ::utility::type_lookup<type_name >::type*)0).operator ,(*(::utility::dummy*)0))
      ^
      <source> : 9 : 5 : note : in expansion of macro 'UTILITY_TYPE_LOOKUP_BY_ERROR'
      UTILITY_TYPE_LOOKUP_BY_ERROR(STATIC_ASSERT_PARAM(static_param))
      ^
      <source> : 36 : 1 : note : in expansion of macro 'UTILITY_PARAM_LOOKUP_BY_ERROR'
      UTILITY_PARAM_LOOKUP_BY_ERROR(sizeof(test));
      ^
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-26
        • 2017-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-22
        • 2012-07-01
        • 2013-01-15
        相关资源
        最近更新 更多