Integrate type name in static_assert output?

后端 未结 5 883
独厮守ぢ
独厮守ぢ 2020-12-04 18:56

I like to give helpful errors / messages, and I also want to do so for my static_asserts. The problem is, that they depend on template parameters. Normally, tho

相关标签:
5条回答
  • 2020-12-04 19:28

    If your compiler provides the __FUNCTION__ macro, you can have a really simple substitution using it and literal concatenation. However, gcc's and clang's implementation is not done as a macro, so this solution will not work for them.

    #include "stdafx.h"
    #include <type_traits>
    
    template <class T>
    class must_be_pod
    {
        static void test() { static_assert (std::is_pod<T>::value, __FUNCTION__ ": not a POD"); }
    public:
        must_be_pod() { test(); }
    };
    
    class not_a_pod
    {
    public:
        not_a_pod() {}
        virtual ~not_a_pod() {}
    };
    
    int main()
    {
        must_be_pod<not_a_pod> should_fail; // and it does
        return 0;
    }
    

    This produces the following output when compiled by VS2015:

    static_assert_test.cpp(10): error C2338: must_be_pod<class not_a_pod>::test: not a POD
    
    0 讨论(0)
  • 2020-12-04 19:36

    It's possible to get a string literal passed in as a template non-type parameter, with a little bit of hoop-jumping. But since the second argument to static_assert is constrained to be a string literal rather than, say, an address constant expression, this unfortunately is not much use.

    Sadly I suspect your best bet is to lobby the committee or the compiler writers to extend the facility.

    0 讨论(0)
  • 2020-12-04 19:44

    My Hack

    Code:

    template <typename Assertion>
    struct AssertValue : AssertionChecker<Assertion::value, Assertion>
    {
        static_assert(AssertionValue, "Assertion failed <see below for more information>");
        static bool const value = Assertion::value;
    };
    

    It allows for you to check any ::value assertion and dump the types if it failed.

    Usage:

    // Bad indentation used to show parts
    static_assert(
        AssertValue<
            std::my_check<
                T0, decltype(*somethingComplicated), T7::value_type
            >
        >, 
        "something horrible happened"
    );
    

    where std::my_check<...>::value is the boolean result of the check

    Example

    For a full SSCCE example see: IDEOne Example

    The Example's error message:

    prog.cpp: In instantiation of 'AssertValue<std::is_base_of<IMyInterface, MyBadType> >':
    prog.cpp:37:69:   instantiated from 'void MyFunction(IteratorType, IteratorType) [with IteratorType = __gnu_cxx::__normal_iterator<MyBadType*, std::vector<MyBadType> >]'
    prog.cpp:60:38:   instantiated from here
    prog.cpp:9:5: error: static assertion failed: "Assertion failed <see below for more information>"
    prog.cpp: In function 'void MyFunction(IteratorType, IteratorType) [with IteratorType = __gnu_cxx::__normal_iterator<MyBadType*, std::vector<MyBadType> >]':
    prog.cpp:60:38:   instantiated from here
    prog.cpp:39:5: error: static assertion failed: "iterator passed does not reference IMyInterface items"
    

    Explanation

    If the assertion fails, it will print the template arguments of AssertValue and therefore print the full template expansion of your check. For example, if you were checking a std::is_base_of it will print the full type of the check, e.g.: std::is_base_of<IMyInterface, MyBadType>. Then you know exactly what types were used in the failed assertion.

    The only problem is that this only works on templates that put their result in ::value. However type_traits mostly uses this and is the goto standard.

    0 讨论(0)
  • 2020-12-04 19:45

    std::type_info has a member const char* name():

    #include <typeinfo>
    using namespace std;
    
    //...
    
    const char* name = type_info(T).name();
    
    0 讨论(0)
  • 2020-12-04 19:48

    I see this has been answered a while ago, but the full answer was lost, and I found a very simply way to achieve the desired result.

    template <typename T, bool value>
    static typename std::enable_if<value, void>::type FunctionWithReadableErrorMessage()
    {
    }
    
    
    int  main()
    {
        FunctionWithReadableErrorMessage<int, false>();
        return 0;
    }
    

    This function will compile and have no effect if value=true, otherwise we get this error message:

    main.cpp: In function 'int main()': main.cpp:16:50: error: no matching function for call to 'FunctionWithReadableErrorMessage()' FunctionWithReadableErrorMessage(); ^

    If we wanna be a bit more general we can put it in a macro

    0 讨论(0)
提交回复
热议问题