IT

static_assert의 기능은 무엇이며 어떤 용도로 사용 하시겠습니까?

lottoking 2020. 8. 3. 17:27
반응형

static_assert의 기능은 무엇이며 어떤 용도로 사용 하시겠습니까?


static_assert(...)( 'C ++ 11')이 문제를 우아하게 해결할 수있는 예를 들어 주 시겠습니까?

나는 사용에 익숙하다 assert(...). 언제 static_assert(...)정기적으로 선호 assert(...)합니까?

또한라는 것이 boost있는데 BOOST_STATIC_ASSERT, 같은 것 static_assert(...)입니까?


내 머리에서 ...

#include "SomeLibrary.h"

static_assert(SomeLibrary::Version > 2, 
         "Old versions of SomeLibrary are missing the foo functionality.  Cannot proceed!");

class UsingSomeLibrary {
   // ...
};

그것이 C SomeLibrary::Version가 아닌 정적 const로 선언 가정하면 #define(C ++ 라이브러리에서 기대하는 것처럼).

컴파일 실제로 SomeLibrary하고 코드를 작성 하고 모든 것을 연결 한 다음 실행 파일을 실행해야 우리 호환되지 않는 버전의 컴파일하는 데 30 분이 걸린다는 것을 알 수 있습니다 SomeLibrary.

@Arak, 귀하의 의견에 대한 답변 : 예, static_assert어디서나 앉아 있을 수 있습니다 :

class Foo
{
    public: 
        static const int bar = 3;
};

static_assert(Foo::bar > 4, "Foo::bar is too small :(");

int main()
{ 
    return Foo::bar;
}
$ g ++ --std = c ++ 0x a.cpp
a.cpp : 7 : 오류 : 정적 어설 션이 실패했습니다 : "Foo :: bar가 너무 작습니다 :("

정적 어설 션은 만드는 타임에 어설 션을 만드는 데 사용됩니다. 정적 어설 션이 실패하면 프로그램은 없습니다. 이는 동일한 예를 들어 unsigned int정확히 32 비트를 가진 기능에 크게 의존하는 코드로 일부를 구현하는 경우에 유용합니다 . 이런 식으로 정적 assert를 넣을 수 있습니다.

static_assert(sizeof(unsigned int) * CHAR_BIT == 32);

귀하의 코드에서. 크기가 다른 unsigned int유형의 다른 플랫폼에서는 문제가있는 부분에주의를 기울이고 다시 구현하거나 검사하도록 조언합니다.

다른 예를 들어, void *함수에 대한 포인터 로 일부 적분 값을 전달하고 (때는 유용하지만) 적분 값이 포인터에 맞는지 확인하려는 경우

int i;

static_assert(sizeof(void *) >= sizeof i);
foo((void *) i);

해당 char유형이 서명 된 자산을 원할 수 있습니다.

static_assert(CHAR_MIN < 0);

0으로 반올림합니다.

static_assert(-5 / 2 == -2);

등등.

대부분의 경우 정적 어설 션 대신 작동 어설 션을 사용할 수 있습니다. 지금은 실패한 작동이 없습니다.

정적 어설 션의 식은 물론 타임 상 수집합니다. 작동 값이 될 수 없습니다. 런타임 값의 경우 다른 선택 방법이 없지만 일반을 사용하십시오 assert.


컴파일러 동작, 헤더, 라이브러리 및 심지어 내 코드에 대한 가정이 올바른지 확인하는 데 사용합니다. 예를 들어에서 제공되는 것이 예상 크기로 여기에서 확인합니다.

struct LogicalBlockAddress
{
#pragma pack(push, 1)
    Uint32 logicalBlockNumber;
    Uint16 partitionReferenceNumber;
#pragma pack(pop)
};
BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6);

클래스 포장에서 stdio.hfseek(), 나는 몇 가지 바로 가기를 촬영 한 enum Origin그 바로 가기에 의해 정의 된 상수와 맞게 연결되어 있는지 체크stdio.h

uint64_t BasicFile::seek(int64_t offset, enum Origin origin)
{
    BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET);

당신은 좋아한다 static_assert이상 assert동작이 같은 내가 주어진 한 예로, 때에 정의, 그리고 실행에. 예 이것이 없는 경우는 매개 변수와 반환 코드 검사를 포함한다.

BOOST_STATIC_ASSERT조건이 생성되지 않는 오류 코드를 생성하는 C ++ 0x 이전 매크로입니다. 는 동일하지만 의도 static_assert표준화 되었지만 더 나은 컴파일러 진단을 제공 할 수 있습니다.


BOOST_STATIC_ASSERTstatic_assert기능을 위한 크로스 플랫폼 래퍼입니다 .

현재 저는 클래스에 "개념"을 적용하기 위해 static_assert를 사용하고 있습니다.

예:

template <typename T, typename U>
struct Type
{
  BOOST_STATIC_ASSERT(boost::is_base_of<T, Interface>::value);
  BOOST_STATIC_ASSERT(std::numeric_limits<U>::is_integer);
  /* ... more code ... */
};

위의 조건 중 하나라도 충족되지 않으면 컴파일 시간 오류가 발생합니다.


의 한 가지 용도는 static_assert구조 (네트워크 또는 파일과 같은 외부 세계와의 인터페이스)가 예상 한 크기와 정확히 일치하는지 확인하는 것입니다. 이것은 누군가가 결과를 깨닫지 못하고 구조에서 멤버를 추가하거나 수정하는 경우를 포착합니다. static_assert그것을 선택하고 사용자에게 경고합니다.


개념이없는 경우 static_assert템플릿에서와 같이 간단하고 읽기 쉬운 컴파일 타임 유형 검사에 사용할 수 있습니다 .

template <class T>
void MyFunc(T value)
{
static_assert(std::is_base_of<MyBase, T>::value, 
              "T must be derived from MyBase");

// ...
}

이것은 원래의 질문에 직접 답하지는 않지만 C ++ 11 이전에 이러한 컴파일 시간 검사를 시행하는 방법에 대한 흥미로운 연구를 만듭니다.

Andrei Alexanderscu Modern C ++ Design 2 장 (섹션 2.1)은 다음과 같은 컴파일 타임 어설 션 아이디어를 구현합니다.

template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};

#define STATIC_CHECK(expr, msg) \
{ CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

매크로 STATIC_CHECK () 및 static_assert () 비교

STATIC_CHECK(0, COMPILATION_FAILED);
static_assert(0, "compilation failed");

는 다음과 같은 방식으로 키워드 static_assert사용을 금지하는 데 사용할 수 있습니다 delete.

#define delete static_assert(0, "The keyword \"delete\" is forbidden.");

모든 최신 C ++ 개발자는 보수적 가비지 수집기 의 보수적 힙에 메모리를 할당하는 함수를 호출하기 위해 new 연산자 를 오버로드하는 클래스 es 및 struct 를 사용하여 보수적 가비지 수집기를 사용하려는 경우이를 수행 할 수 있습니다. 함수의 시작 부분에서이를 수행하는 일부 함수를 호출하여 초기화 및 인스턴스화 할 수 있습니다 .main

예를 들어 Boehm-Demers-Weiser 보수적 가비지 수집기를 사용하려는 모든 최신 C ++ 개발자는 main함수 시작 부분에 다음과 같이 작성합니다.

GC_init();

그리고 모든 년 classstruct과부하 operator new이런 식으로 :

void* operator new(size_t size)
{
     return GC_malloc(size);
}

그리고 이제는 operator delete더 이상 필요하지 않습니다. Boehm-Demers-Weiser 보수적 가비지 수집기가 더 이상 필요하지 않을 때 모든 메모리 블록을 해제하고 할당 해제해야하기 때문에 개발자는 delete키워드 를 금지하려고 합니다.

한 가지 방법은 다음과 같이 오버로드하는 delete operator것입니다.

void operator delete(void* ptr)
{
    assert(0);
}

그러나 이것은 권장되지 않습니다. 현대의 C ++ 개발자는 자신 delete operator이 런타임에 실수로를 호출했음을 알 수 있기 때문에 컴파일 타임에 이것을 곧 아는 것이 좋습니다.

따라서이 시나리오에 대한 가장 좋은 해결책 static_assert은이 답변의 시작 부분에 표시된 것처럼 사용하는 것입니다.

물론 이것은로도 할 수 BOOST_STATIC_ASSERT있지만 나는 그것이 static_assert더 낫고 항상 더 선호되어야 한다고 생각합니다 .

참고 URL : https://stackoverflow.com/questions/1647895/what-does-static-assert-do-and-what-would-you-use-it-for

반응형