Integrate type name in static_assert output?

為{幸葍}努か 提交于 2019-11-27 18:27:31

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.

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.

Spencer

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

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

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

#include <typeinfo>
using namespace std;

//...

const char* name = type_info(T).name();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!