함수 내부의 정적 constexpr 변수가 의미가 있습니까?


193

내가 함수 내에서 (예를 들어, 큰 배열을) 변수가 있다면, 그것은 두 선언은 의미가 수행 static하고에게 constexpr? constexpr컴파일 타임에 배열이 생성되도록 보장하므로 static쓸모가 없습니까?

void f() {
    static constexpr int x [] = {
        // a few thousand elements
    };
    // do something with the array
}

는 IS static생성 된 코드 또는 의미의 측면에서이 실제로 일을 아무것도?

답변:


230

짧은 대답은 static유용 할뿐만 아니라 항상 원할 것입니다.

첫째, 그 노트 static와는 constexpr서로 완전히 독립적입니다. static실행 중 객체의 수명을 정의합니다. constexpr컴파일 중에 오브젝트를 사용할 수 있도록 지정합니다. 컴파일과 실행은 시간과 공간 모두에서 분리되고 불 연속적입니다. 따라서 프로그램이 컴파일되면 constexpr더 이상 관련이 없습니다.

선언 된 모든 변수는 constexpr암시입니다 constconststatic거의 직교 (과의 상호 작용을 제외하고 static const정수.)

C++객체 모델 (§1.9)의 모든 비트 필드는 메모리의 적어도 하나의 바이트를 차지하고 주소가 아닌 다른 오브젝트해야; 또한 주어진 순간에 프로그램에서 관찰 할 수있는 그러한 모든 객체는 별개의 주소를 가져야한다 (문단 6). 컴파일러는 로컬 비 정적 const 배열로 함수를 호출 할 때마다 스택에 새 배열을 만들 필요가 없습니다. 컴파일러는 as-if원칙적으로 피난처를 취할 수 있기 때문에 다른 객체가 없다는 것을 증명할 수 있기 때문입니다 관찰했다.

정의가 다소간에 배열이 주소이기 때문에 함수가 사소하지 않으면 (예를 들어, 번역 단위 내에서 본문이 보이지 않는 다른 함수를 호출하지 않는 한) 안타깝게도 쉽게 증명할 수 없습니다. 따라서 대부분의 경우 정적이 아닌 const(expr)배열은 호출 할 때마다 스택에서 다시 작성해야하므로 컴파일시 배열을 계산할 수있는 지점을 잃게됩니다.

반면, 로컬 static const객체는 모든 옵저버가 공유하며, 정의 된 함수가 호출되지 않더라도 초기화 될 수 있습니다. 따라서 위의 어느 것도 적용되지 않으며 컴파일러는 단일 인스턴스 만 생성 할뿐 아니라 자유롭게 사용할 수 있습니다. 읽기 전용 스토리지에서 인스턴스 하나를 자유롭게 생성 할 수 있습니다.

따라서 static constexpr귀하의 예에서 분명히 사용해야 합니다.

그러나을 사용하고 싶지 않은 경우가 있습니다 static constexpr. 않는 constexpr선언 된 개체 중 하나입니다 ODR-사용 또는 선언이 static컴파일러는 전혀 포함시키지 무료입니다. constexpr불필요한 바이트로 컴파일 된 프로그램을 오염시키지 않고 컴파일 타임 임시 배열을 사용할 수 있기 때문에 매우 유용 합니다. 이 경우 런타임에 객체가 존재하게 될 가능성이 static있으므로 를 사용하고 싶지 않습니다 static.


2
@AndrewLazarus, 당신은 멀리 캐스팅 할 수없는 constA로부터 const만에서, 객체 const X*에있는 점 X. 그러나 그것은 요점이 아닙니다. 요점은 자동 객체는 고정 주소를 가질 수 없다는 것입니다. 내가 말했듯이, constexpr컴파일이 완료되면 의미가 없어 지므로 캐스트 할 것이 없습니다 (객체가 런타임에 존재한다고 보장되지 않기 때문에 아마도 아무것도 없습니다)
rici

17
나는이 대답이 믿을 수 없을 정도로 혼란스럽고 자기 모순적 인 것처럼 느껴집니다. 예를 들어, 당신은 당신이 거의 항상 원하는 말을 static하고 constexpr있지만 서로 다른 일을하고, 직교 및 독립적이라고 설명한다. 그런 다음 ODR 사용을 무시하므로 유용하지 않은 두 가지를 결합하지 않는 이유를 언급합니다. 정적이 런타임 용이므로 constexpr과 함께 정적을 사용해야하는 이유는 여전히 알지 못합니다. constexpr을 사용하여 static이 중요한 이유를 설명하지 않았습니다.
void.pointer

2
@ void.pointer : 당신은 마지막 단락에 대해 맞습니다. 나는 소개를 바꿨다. 나는 static constexpr( 중요한 배열이 모든 함수 호출에서 다시 작성되는 것을 막는다) 의 중요성을 설명했다고 생각 했지만 더 명확하게 할 수있는 단어를 수정했습니다. 감사.
rici

8
컴파일 시간 상수와 런타임 상수를 언급하는 것도 유용 할 수 있습니다. 즉, constexpr상수 변수가 컴파일 타임 컨텍스트에서만 사용되고 런타임에는 필요 static하지 않으면 런타임에 도달 할 때까지 값이 효과적으로 "인라인"되었으므로 의미가 없습니다. 그러나 constexpr런타임 컨텍스트에서 사용되는 경우 (즉, 암시 적 constexpr으로 변환해야 const하며 런타임 코드의 실제 주소로 사용 가능 static해야 함) ODR 준수 등을 보장해야합니다. 적어도 내 이해입니다.
void.pointer

3
마지막 코멘트의 예 : static constexpr int foo = 100;. 코드가 다음과 같은 작업을 수행하지 않는 한 컴파일러가 foo리터럴 대신 모든 곳의 사용을 대체 할 수없는 이유는 없습니다 . 따라서 런타임에는 존재하지 않기 때문에 on 은이 경우 유용 하지 않습니다. 다시 컴파일러까지 모두. 100&foostaticfoofoo
void.pointer

10

주어진 대답뿐만 아니라, 그 컴파일러를 지적 그것의 가치는 초기화 할 필요가 없습니다 constexpr차이 것을 알고, 컴파일시에 변수 constexprstatic constexpr그 사용하는 것입니다 static constexpr당신이 변수가 한 번만 초기화되어 있는지 확인합니다.

다음 코드는 constexpr변수가 여러 번 (동일한 값으로) static constexpr초기화 되는 반면 한 번만 초기화 되는 방법을 보여줍니다 .

또한 코드는 constexpr와의 const조합 에 대한 장점을 비교합니다 static.

#include <iostream>
#include <string>
#include <cassert>
#include <sstream>

const short const_short = 0;
constexpr short constexpr_short = 0;

// print only last 3 address value numbers
const short addr_offset = 3;

// This function will print name, value and address for given parameter
void print_properties(std::string ref_name, const short* param, short offset)
{
    // determine initial size of strings
    std::string title = "value \\ address of ";
    const size_t ref_size = ref_name.size();
    const size_t title_size = title.size();
    assert(title_size > ref_size);

    // create title (resize)
    title.append(ref_name);
    title.append(" is ");
    title.append(title_size - ref_size, ' ');

    // extract last 'offset' values from address
    std::stringstream addr;
    addr << param;
    const std::string addr_str = addr.str();
    const size_t addr_size = addr_str.size();
    assert(addr_size - offset > 0);

    // print title / ref value / address at offset
    std::cout << title << *param << " " << addr_str.substr(addr_size - offset) << std::endl;
}

// here we test initialization of const variable (runtime)
void const_value(const short counter)
{
    static short temp = const_short;
    const short const_var = ++temp;
    print_properties("const", &const_var, addr_offset);

    if (counter)
        const_value(counter - 1);
}

// here we test initialization of static variable (runtime)
void static_value(const short counter)
{
    static short temp = const_short;
    static short static_var = ++temp;
    print_properties("static", &static_var, addr_offset);

    if (counter)
        static_value(counter - 1);
}

// here we test initialization of static const variable (runtime)
void static_const_value(const short counter)
{
    static short temp = const_short;
    static const short static_var = ++temp;
    print_properties("static const", &static_var, addr_offset);

    if (counter)
        static_const_value(counter - 1);
}

// here we test initialization of constexpr variable (compile time)
void constexpr_value(const short counter)
{
    constexpr short constexpr_var = constexpr_short;
    print_properties("constexpr", &constexpr_var, addr_offset);

    if (counter)
        constexpr_value(counter - 1);
}

// here we test initialization of static constexpr variable (compile time)
void static_constexpr_value(const short counter)
{
    static constexpr short static_constexpr_var = constexpr_short;
    print_properties("static constexpr", &static_constexpr_var, addr_offset);

    if (counter)
        static_constexpr_value(counter - 1);
}

// final test call this method from main()
void test_static_const()
{
    constexpr short counter = 2;

    const_value(counter);
    std::cout << std::endl;

    static_value(counter);
    std::cout << std::endl;

    static_const_value(counter);
    std::cout << std::endl;

    constexpr_value(counter);
    std::cout << std::endl;

    static_constexpr_value(counter);
    std::cout << std::endl;
}

가능한 프로그램 출력 :

value \ address of const is               1 564
value \ address of const is               2 3D4
value \ address of const is               3 244

value \ address of static is              1 C58
value \ address of static is              1 C58
value \ address of static is              1 C58

value \ address of static const is        1 C64
value \ address of static const is        1 C64
value \ address of static const is        1 C64

value \ address of constexpr is           0 564
value \ address of constexpr is           0 3D4
value \ address of constexpr is           0 244

value \ address of static constexpr is    0 EA0
value \ address of static constexpr is    0 EA0
value \ address of static constexpr is    0 EA0

보시다시피 키워드는 초기화가 한 번만 수행되도록하는 constexpr동안 여러 번 static초기화됩니다 (주소는 동일하지 않음) .


constexpr_short 가 다시 초기화 constexpr const short constexpr_short되면 에러를 줄 수 없습니다
akhileshzmishra

이미 구문이 constexpr const의미가 없으므로 컴파일러는 한 번 또는 여러 번 추가하는 것을 무시합니다. 오류를 잡으려고하지만 오류가 아닙니다. 대부분의 컴파일러가 작동합니다. constexprconstconst
메타 블라스터
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.