컴파일 타임에 문자열 리터럴의 길이를 계산하려고합니다. 이를 위해 다음 코드를 사용하고 있습니다.
#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
있는지가 컴파일시에 평가 될 변수, 우리는에서이 볼 수 11 참조 ++ 비얀 스트로브 스트 룹의 C (라고 강조 광산 ) :
컴파일 타임에 표현식을 평가할 수있을뿐만 아니라 컴파일 타임에 표현식을 평가 하도록 요구할 수 있습니다. 변수 정의 앞의 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;
}
답변
답변
재귀 적이 지 않고 컴파일 타임에 문자열의 길이를 계산하는 또 다른 함수를 제안하겠습니다.
template< size_t N >
constexpr size_t length( char const (&)[N] )
{
return N-1;
}
ideone 에서이 샘플 코드를 살펴보십시오 .
답변
constexpr
합당한 컴파일러가 활성화 된 적절한 최적화 수준에서 수행 할 것이지만 함수가 컴파일 타임에 평가 된다는 보장은 없습니다 . 반면에, 템플릿 매개 변수 는 컴파일 타임에 평가 되어야합니다 .
컴파일 타임에 강제로 평가하기 위해 다음 트릭을 사용했습니다. 불행히도 정수 값으로 만 작동합니다 (즉, 부동 소수점 값으로는 작동하지 않음).
template<typename T, T V>
struct static_eval
{
static constexpr T value = V;
};
자, 쓰면
if (static_eval<int, length("hello, world")>::value > 7) { ... }
if
명령문이 런타임 오버 헤드가없는 컴파일 타임 상수 임을 확인할 수 있습니다 .
답변
일반화 상수 표현식 에 대한 Wikipedia 항목의 간단한 설명 :
함수에 constexpr을 사용하면 해당 함수가 수행 할 수있는 작업에 몇 가지 제한이 있습니다. 첫째, 함수는 무효가 아닌 반환 유형을 가져야합니다. 둘째, 함수 본문은 변수를 선언하거나 새로운 유형을 정의 할 수 없습니다. 셋째, 본문에는 선언, null 문 및 단일 return 문만 포함될 수 있습니다. 인수 대체 후 return 문의식이 상수 식을 생성하는 인수 값이 있어야합니다.
constexpr
함수 정의 앞에 키워드가 있으면 컴파일러가 이러한 제한 사항이 충족되는지 확인하도록 지시합니다. 그렇다면 상수를 사용하여 함수를 호출하면 반환 된 값이 상수임을 보장하므로 상수 표현식이 필요한 모든 곳에서 사용할 수 있습니다.