ProgramingTip

C ++에서 배열 타임에 프로그래밍 방식으로 정적 배열 만들기

bestdevel 2020. 11. 21. 09:29
반응형

C ++에서 배열 타임에 프로그래밍 방식으로 정적 배열 만들기


여기서 타임에 다음과 같이 정적 배열을 정의 할 수 있습니다.

const std::size_t size = 5;    
unsigned int list[size] = { 1, 2, 3, 4, 5 };

질문 1- 다양한 종류의 메타 프로그래밍 기술을 사용하여 준비 타임에 적절한 값을 "프로그래밍 방식"으로 할당하는 것이 가능합니까?

질문 2- 배열의 모든 값이 몇 가지 동일한 값이라고 가정하면 할 타임에 프로그래밍 방식으로 값을 선택적으로 할당 수 있습니까?

예 :

const std::size_t size = 7;        
unsigned int list[size] = { 0, 0, 2, 3, 0, 0, 0 };
  1. C ++ 0x를 사용하는 솔루션은 환영합니다.
  2. 배열은 보유하고 있습니다.
  3. 현재 어레이는 POD 유형으로 만 구성됩니다.
  4. 또한 배열의 크기가 정적 방식으로 미리 알려질 가정 할 수 있습니다.
  5. 솔루션은 C ++이어야합니다 (서비스 없음, 매크로 없음, pp 또는 코드 생성기 기반 솔루션 pls 없음).

업데이트 : Georg Fritzsche의 솔루션은 놀랍고 msvc 및 인텔 컴파일러에서 그럼에도 불구하고 약간의 작업이 필요하지만 매우 흥미로운 접근 방식이 필요합니다.


가장 가까운 방법은 C ++ 0x 기능을 사용하여 가변 템플릿 인수 목록에서 템플릿의 로컬 또는 멤버 배열을 초기화하는 것입니다.
이는 실질적인 최대 템플릿 인스턴스화 깊이에 의해 제한되는 실제로의 경우에 현저한 차이를 만드는 정도를합니다.

예 :

template<unsigned... args> struct ArrayHolder {
    static const unsigned data[sizeof...(args)];
};

template<unsigned... args> 
const unsigned ArrayHolder<args...>::data[sizeof...(args)] = { args... };

template<size_t N, template<size_t> class F, unsigned... args> 
struct generate_array_impl {
    typedef typename generate_array_impl<N-1, F, F<N>::value, args...>::result result;
};

template<template<size_t> class F, unsigned... args> 
struct generate_array_impl<0, F, args...> {
    typedef ArrayHolder<F<0>::value, args...> result;
};

template<size_t N, template<size_t> class F> 
struct generate_array {
    typedef typename generate_array_impl<N-1, F>::result result;
};

귀하의 경우 1..5대한 사용법 :

template<size_t index> struct MetaFunc { 
    enum { value = index + 1 }; 
};

void test() {
    const size_t count = 5;
    typedef generate_array<count, MetaFunc>::result A;

    for (size_t i=0; i<count; ++i) 
        std::cout << A::data[i] << "\n";
}

당신의 요구 사항이 너무 모호해서에 대해 아무것도하기 어렵습니다 ... 물론 주요 문제는 그 가치는 어디에서 오는가?

어쨌든 C ++로 빌드하는 단계에서 생각할 수 있습니다.

  • 빌드 전 단계 생성 : 다른 형식의 헤더 / 소스 펼쳐보기
  • 전처리
  • 템플릿 인스턴스화
  • 적당한

펼쳐 생성을 배제하고 전처리와 메타 템플릿 프로그래밍의 두 가지 대안이 남습니다.

내가 아는 것이없는 한 존재 타임에 두 개의 배열을 강화하기 때문에 메타 템플릿 프로그래밍이 여기서 트릭을 수행하는 방법을 알 수 있습니다. 따라서 우리는 오늘의 구원자 : 전 처리기 프로그래밍

우리를 돕기 위해 본격적인 라이브러리를 사용하는 것이 좋습니다 : Boost.Preprocessor .

여기에서 관심이 있습니다.

이제 우리가 값을 어디에서 고를 지 알았다면 더 의미있는 예를 제시 할 수 있습니다.


템플릿을 사용하여 중첩 된 배열을 빌드하고 올바른 유형의 배열로 캐스팅하는 것은 어떻습니까? 아래의 예는 저에게도 정의되지 않은 행동에 매우 가깝게 밟거나 걷는 느낌이 있습니다.

#include <iostream>

template<int N>
struct NestedStruct
{
  NestedStruct<N-1> contained;
  int i;
  NestedStruct<N>() : i(N) {}
};

template<>
struct NestedStruct<0> 
{
  int i;
  NestedStruct<0>() : i(0) {}
};

int main()
{
  NestedStruct<10> f;
  int *array = reinterpret_cast<int*>(&f);
  for(unsigned int i=0;i<10;++i)
  {
    std::cout<<array[i]<<std::endl;
  }
}

그리고 물론 여러분은 배열이 없다고 주장 할 수 있습니다. (불가능하다고 주장 할 수 있습니다).하지만 배열에 값은 배열 타임에 계산하고, 배열처럼 접근 할 수 있습니다. 나는 당신이 얻을 수있는 한 가깝다고 생각합니다.


정말 컴파일러 시간에해야할까요? 정적 시간 초기화에 수행하는 것이 훨씬 뛰어납니다. 이런 식으로 할 수 있습니다.

#include <cstddef>
#include <algorithm>

template<std::size_t n>
struct Sequence
{
    int list[n];

    Sequence()
    {
        for (std::size_t m = 0; m != n; ++m)
        {
            list[m] = m + 1;
        }
    }
};

const Sequence<5> seq1;

struct MostlyZero
{
    int list[5];

    MostlyZero()
    {
        std::fill_n(list, 5, 0); // Not actually necessary if our only
                                 // are static as static objects are
                                 // always zero-initialized before any
                                 // other initialization
        list[2] = 2;
        list[3] = 3;
    }
};

const MostlyZero mz1;

#include <iostream>
#include <ostream>

int main()
{
    for (std::size_t n = 0; n != 5; ++n)
    {
        std::cout << seq1.list[n] << ", " << mz1.list[n] << '\n';
    }
}

원하는 경우 목록을 외부로 밀어 넣을 수 있습니다 이와 같이 조금 더 깔끔한 생각했습니다.


Boost.Assignment 와 같은 것이 표준 컨테이너에서 작동 할 수 있습니다. 정말로 배열을 사용해야하는 경우 Boost.Array 와 함께 사용할 수 있습니다 .


언젠가는 그러한 배열이 유형 배열에서 생성됩니다. 예를 들어 이미 가변 클래스 목록 (예 : 템플릿)이 있고 캡슐화 된 uint32_t 값을 저장하려면 다음을 사용할 수 있습니다.

uint32_t tab[sizeof(A)]= {A::value...};

1 '질문이 없습니다. 그렇게 할 수 있습니다.

template <int num, int cur>
struct ConsequentListInternal {
    enum {value = cur};
    ConsequentListInternal<num-1,cur+1> next_elem;
};

template <int cur>
struct ConsequentListInternal<0, cur> {
    enum {value = cur};
};

template <int v>
struct ConsequentList {
    ConsequentListInternal<v, 0> list;
};

int main() {
    ConsequentList<15> list;
    return 0;
}

메타 프로그래밍으로 할 수있는 일이 많이 있습니다. 그러나 먼저 질문하고 싶습니다. 왜 당신의 경우에 이것을하고 싶습니까? 나는 당신이 다른 장소에서 그러한 배열을 선언해야하는지 이해할 수 있었기 때문에 같은 것을 여러 번 다시 작성해야 할 것입니다. 이것이 당신의 경우입니까?

"프로그래밍 방식으로 정의"라고 말함으로써 다음을 제안합니다.

#define MyArr(macro, sep) \
    macro(0) sep \
    macro(0) sep \
    macro(2) sep \
    macro(3) sep \
    macro(0) sep \
    macro(0) sep \
    macro(0)

지금까지 가장 추상적 인 방식으로 원하는 모든 값을 정의했습니다. 이러한 값이 실제로 의미가있는 경우 BTW-선언에 추가 할 수 있습니다.

#define MyArr(macro, sep) \
    macro(0, Something1) sep \
    macro(0, Something2) sep \
    // ...

이제 위의 선언에 생명을 불어 넣어 봅시다.

#define NOP
#define COMMA ,
#define Macro_Count(num, descr) 1
#define Macro_Value(num, descr) num

const std::size_t size = MyArr(Macro_Count, +); 
unsigned int list[size] = { MyArr(Macro_Value, COMMA) };

대부분의 배열 항목이 동일한 상황을 처리 할 수도 있습니다.

하지만 항상 스스로에게 물어봐야합니다. 이것이 정말 그만한 가치가 있습니까? 보시다시피 코드를 퍼즐로 바꿉니다.


부스트에서

boost::mpl::range_c<int,1,5>

컴파일 타임에 1에서 5까지 정렬 된 숫자 목록을 생성합니다. 두 번째로 값이 변경 될 기준을 언급하지 않습니다. 목록이 생성되면 정의를 해제 한 다음 새 변수를 다시 정의 할 수 없다고 확신합니다.


코드 생성기를 사용하십시오. 테이블 또는 수학 함수를 사용하여 원하는 코드를 생성 할 수있는 하나 이상의 템플릿을 만듭니다. 그런 다음 앱에서 생성 한 파일을 포함합니다.

진지하게, 코드 생성기는 당신의 삶을 훨씬 쉽게 만들어 줄 것입니다.

참고 URL : https://stackoverflow.com/questions/2978259/programmatically-create-static-arrays-at-compile-time-in-c

반응형