컴파일 타임에 C 문자열의 길이를 계산합니다. 이것은 정말로 constexpr입니까?
컴파일 타임에 문자열 리터럴의 길이를 계산하려고합니다. 이를 위해 다음 코드를 사용하고 있습니다.
#include <cstdio>
int constexpr length(const char* str)
{
return *str ? 1 + length(str + 1) : 0;
}
int main()
{
printf("%d %d", length("abcd"), length("abcdefgh"));
}
모든 것이 예상대로 작동하고 프로그램은 4와 8을 인쇄합니다. clang에 의해 생성 된 어셈블리 코드는 결과가 컴파일 시간에 계산됨을 보여줍니다.
0x100000f5e: leaq 0x35(%rip), %rdi ; "%d %d"
0x100000f65: movl $0x4, %esi
0x100000f6a: movl $0x8, %edx
0x100000f6f: xorl %eax, %eax
0x100000f71: callq 0x100000f7a ; symbol stub for: printf
내 질문 : length
함수가 컴파일 시간에 평가된다는 것이 표준에 의해 보장 됩니까?
이것이 사실이라면 컴파일 타임 문자열 리터럴 계산의 문이 방금 열렸습니다 ... 예를 들어 컴파일 타임에 해시를 계산할 수 있습니다.
상수 표현식은 컴파일 시간에 평가된다는 보장이 없습니다. C ++ 표준 섹션 5.19
상수 표현식 초안 의 비 규범 적 인용 만 있습니다.
[...]> [참고 : 변환 중에 상수 표현식을 평가할 수 있습니다 .—end note]
결과를 constexpr
변수에 할당하여 컴파일 타임에 평가되는지 확인할 수 있습니다. Bjarne Stroustrup의 C ++ 11 참조 에서 확인할 수 있습니다. ( emphasis mine ) :
컴파일 타임에 표현식을 평가할 수있을뿐만 아니라 컴파일 타임에 표현식을 평가 하도록 요구할 수 있기를 원합니다 . 변수 정의 앞의 constexpr은 그렇게합니다 (그리고 const를 의미합니다) :
예를 들면 :
constexpr int len1 = length("abcd") ;
Bjarne Stroustrup은이 isocpp 블로그 항목 에서 컴파일 시간 평가를 보장 할 수있는시기에 대한 요약을 제공하며 다음 과 같이 말합니다.
[...] 정답은-Herb에서 언급했듯이-표준에 따라 constexpr 함수는 상수 표현식으로 사용되지 않는 한 컴파일러 시간 또는 런타임에 평가 될 수 있으며,이 경우 컴파일시 평가되어야합니다. -시각. 컴파일 타임 평가를 보장하려면 상수 표현식이 필요한 곳에 사용하거나 (예 : 배열 바인딩 또는 케이스 레이블로)이를 사용하여 constexpr을 초기화해야합니다. 나는 자존심이 강한 컴파일러가 내가 원래 말했던 것을 할 수있는 최적화 기회를 놓치지 않기를 바란다 : "모든 인수가 상수 표현식이라면 constexpr 함수는 컴파일 타임에 평가된다."
따라서 이것은 컴파일 타임에 평가되어야하는 두 가지 경우에 대해 설명합니다.
- 상수 표현식이 필요한 곳에 사용하십시오. 이것은
shall be ... converted constant expression
또는 구문shall be ... constant expression
이 사용되는 초안 표준 ( 예 : 배열 바운드)의 어느 곳에서나 사용됩니다. constexpr
위에서 설명한대로 초기화하는 데 사용하십시오 .
constexpr
함수 호출 이 핵심 상수 표현식을 생성 하는지 아니면 단순히 최적화되고 있는지 확인하는 것은 정말 쉽습니다 .
상수 표현식이 필요한 컨텍스트에서 사용하십시오.
int main()
{
constexpr int test_const = length("abcd");
std::array<char,length("abcdefgh")> test_const2;
}
참고로 최신 컴파일러 (예 : gcc-4.x) strlen
는 일반적으로 내장 함수 로 정의되기 때문에 컴파일 타임에 문자열 리터럴에 대해 수행 합니다 . 최적화가 활성화되지 않았습니다. 결과가 컴파일 시간 상수는 아니지만.
예 :
printf("%zu\n", strlen("abc"));
결과 :
movl $3, %esi # strlen("abc")
movl $.LC0, %edi # "%zu\n"
movl $0, %eax
call printf
Let me propose another function that computes the length of a string at compile time without being recursive.
template< size_t N >
constexpr size_t length( char const (&)[N] )
{
return N-1;
}
Have a look at this sample code at ideone.
There is no guarantee that a constexpr
function is evaluated at compile-time, though any reasonable compiler will do it at appropriate optimization levels enabled. On the other hand, template parameters must be evaluated at compile-time.
I used the following trick to force evaluation at compile time. Unfortunately it only works with integral values (ie not with floating point values).
template<typename T, T V>
struct static_eval
{
static constexpr T value = V;
};
Now, if you write
if (static_eval<int, length("hello, world")>::value > 7) { ... }
you can be sure that the if
statement is a compile-time constant with no run-time overhead.
A short explanation from Wikipedia's entry on Generalized constant expressions:
The use of constexpr on a function imposes some limitations on what that function can do. First, the function must have a non-void return type. Second, the function body cannot declare variables or define new types. Third, the body may contain only declarations, null statements and a single return statement. There must exist argument values such that, after argument substitution, the expression in the return statement produces a constant expression.
Having the constexpr
keyword before a function definition instructs the compiler to check if these limitations are met. If yes, and the function is called with a constant, the returned value is guaranteed to be constant and thus can be used anywhere a constant expression is required.
'program story' 카테고리의 다른 글
PHP의 정적 클래스 이니셜 라이저 (0) | 2020.09.20 |
---|---|
"입력"이벤트에서 백 스페이스 및 del을 감지합니까? (0) | 2020.09.19 |
C #에서 익명 메서드에 yield 문을 포함 할 수없는 이유는 무엇입니까? (0) | 2020.09.19 |
'IEnumerable'유형의 ViewData 항목이 없습니다. (0) | 2020.09.19 |
자바 스크립트 함수 범위 지정 및 호이 스팅 (0) | 2020.09.19 |