programing

static_assert 출력에 유형 이름을 통합 하시겠습니까?

firstcheck 2021. 1. 16. 09:53
반응형

static_assert 출력에 유형 이름을 통합 하시겠습니까?


나는 도움이되는 오류 / 메시지를 제공하는 것을 좋아하며, 내 static_asserts 를 위해 그렇게하고 싶습니다 . 문제는 템플릿 매개 변수에 의존한다는 것입니다. 일반적으로 이러한 매개 변수는 발생한 오류로 인해 도중에 표시되지만 모호하거나 그룹화되어 있지 않으므로 의미가 있습니다. 예:

template<class T>
struct fake_dependency{
  static bool const value = false;
};

template<class T, class Tag>
struct Foo{
  Foo(){}

  template<class OtherTag>
  Foo(Foo<T, OtherTag> const&){
    static_assert(fake_dependency<T>::value, "Cannot create Foo<T,Tag> from Foo<T,OtherTag>.");
  }
};

int main(){
    Foo<int, struct TagA> fA;
    Foo<int, struct TagB> fB(fA);
}

MSVC의 출력 :

src\main.cpp(74): error C2338: Cannot create Foo<T,Tag> from Foo<T,OtherTag>.
          src\main.cpp(84) : see reference to function template instantiation 'Foo<T,Tag>::Foo<main::TagA>(const Foo<T,main::TagA> &)' being compiled
          with
          [
              T=int,
              Tag=main::TagB
          ]

하나의 태그는 함수 템플릿 자체에 언급되고 다른 하나는 클래스 템플릿과 함께 언급됩니다. 별로 좋지 않아. GCC가 출력하는 내용을 살펴 보겠습니다 .

prog.cpp: In constructor 'Foo<T, Tag>::Foo(const Foo<T, OtherTag>&) [with OtherTag = main()::TagA, T = int, Tag = main()::TagB]':
prog.cpp:18:32:   instantiated from here
prog.cpp:12:5: error: static assertion failed: "Cannot create Foo<T,Tag> from Foo<T,OtherTag>."

훨씬 더 좋지만 여전히 실제로있는 곳은 아닙니다 static_assert. 이제 더 많은 매개 변수, 더 많은 템플릿 또는 둘 다를 상상해보십시오. 산산조각

이 문제를 해결하는 한 가지 방법은 두 태그를 템플릿 매개 변수로 사용하는 중간 구조체를 사용하는 것입니다.

template<class Tag, class OtherTag>
struct static_Foo_assert{
    static_assert(fake_dependency<Tag>::value, "Cannot create Foo<T,Tag> from Foo<T,OtherTag>.");
};

template<class T, class Tag>
struct Foo{
  Foo(){}

  template<class OtherTag>
  Foo(Foo<T, OtherTag> const&){
      static_Foo_assert<Tag, OtherTag> x;
  }
};

이제 출력을 다시 볼 수 있습니다.

src\main.cpp(70): error C2338: Cannot create Foo<T,Tag> from Foo<T,OtherTag>.
          src\main.cpp(79) : see reference to class template instantiation 'static_Foo_assert<Tag,OtherTag>' being compiled
          with
          [
              Tag=main::TagB,
              OtherTag=main::TagA
          ]

훨씬 낫다! GCC는 다음과 같이 말합니다 .

prog.cpp: In instantiation of 'static_Foo_assert<main()::TagB, main()::TagA>':
prog.cpp:17:40:   instantiated from 'Foo<T, Tag>::Foo(const Foo<T, OtherTag>&) [with OtherTag = main()::TagA, T = int, Tag = main()::TagB]'
prog.cpp:23:32:   instantiated from here
prog.cpp:8:5: error: static assertion failed: "Cannot create Foo<T,Tag> from Foo<T,OtherTag>."

나쁘지 않은 것 같습니다. 문제 : 오류 메시지 static_assert가 문자열 리터럴이어야 하므로 모든 템플릿에 대해 이러한 구조체를 만들어야 합니다.

이제 내 질문에 대해 : 어떻게 든 유형 이름을 직접 static_assert? 처럼

static_assert(..., "Cannot create Foo<" T "," Tag "> from Foo<" T "," OtherTag ">.");

출력 예 :

Foo<int,main::TagA>에서 만들 수 없습니다 Foo<int,main::TagB>.

또는 달성 할 수없는 경우 어떻게 든 오류 메시지를 추가 템플릿 매개 변수로 만들어 통과 가능하게 만들 수 있습니까?


내 해킹

암호:

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;
};

이를 통해 ::value어설 션 을 확인 하고 실패한 경우 유형을 덤프 할 수 있습니다.

용법:

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

std::my_check<...>::value검사의 부울 결과는 어디 입니까?

전체를 들어 SSCCE의 예를 참조하십시오 IDEOne 예

예제의 오류 메시지 :

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"

설명

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.


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();

ReferenceURL : https://stackoverflow.com/questions/6415186/integrate-type-name-in-static-assert-output

반응형