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 };
- C ++ 0x를 사용하는 솔루션은 환영합니다.
- 배열은 보유하고 있습니다.
- 현재 어레이는 POD 유형으로 만 구성됩니다.
- 또한 배열의 크기가 정적 방식으로 미리 알려질 가정 할 수 있습니다.
- 솔루션은 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까지 정렬 된 숫자 목록을 생성합니다. 두 번째로 값이 변경 될 기준을 언급하지 않습니다. 목록이 생성되면 정의를 해제 한 다음 새 변수를 다시 정의 할 수 없다고 확신합니다.
코드 생성기를 사용하십시오. 테이블 또는 수학 함수를 사용하여 원하는 코드를 생성 할 수있는 하나 이상의 템플릿을 만듭니다. 그런 다음 앱에서 생성 한 파일을 포함합니다.
진지하게, 코드 생성기는 당신의 삶을 훨씬 쉽게 만들어 줄 것입니다.
'ProgramingTip' 카테고리의 다른 글
열 너비가 고정 된 LaTeX 테이블의 셀 내용을 중앙에 배치하는 방법은 무엇입니까? (0) | 2020.11.21 |
---|---|
Android 웹 애플리케이션 구성 (0) | 2020.11.21 |
콘솔 (Ctrl-C)에서 종료 될 때 PyQt 애플리케이션을 종료하는 올바른 방법은 무엇입니까? (0) | 2020.11.21 |
입력 유형 = "텍스트"요소 HTML / CSS 내부 텍스트 기 (0) | 2020.11.21 |
요소가 화면에 표시 확인 (0) | 2020.11.20 |