TLTR : 템플릿 배열의 일부 배열을 가변 배열 템플릿 목록에 저장된 인덱스로 정의 된 특정 순서에 따라 함수의 인수에 매핑하고 싶습니다. (나는 문제를 정의하는 더 간단한 방법을 생각할 수 없다).변수 템플릿과 타입리스트를 사용하여 불투명 한 배열을 함수 인수에 매핑
배열은 void*
을 사용하여 저장되지만 배열 사이의 유형 안전성과 함수 매개 변수는 도우미 클래스에 의해 보장됩니다. 동일한 도우미 클래스는 주어진 매개 변수 팩을 확장하고, 적절한 배열을 가져 와서 함수 포인터에 바인딩하고 함수를 호출해야합니다. 이것은 내가 붙어있는 곳이다.
세부 사항 : 오랜 질문과 게시 코드는 미리 사과하지만 최대한 간결하게하려고 노력했습니다.
문제는 컨테이너의 적절한 구성원을 펑터 개체에 매핑하는 것으로 구성됩니다. 컨테이너에는 typelist에 의해 정의 된 배열 목록이 있으며 구현은 this one과 유사합니다.
간단히하기 위해 입력 목록 도우미 객체 TLAlg::length<TL>
및 TLAlg::TypeAt
이 정의되어 있고 사용자가 입력 목록 및 N 번째 유형의 길이에 각각 액세스 할 수 있다고 가정합니다.
컨테이너 클래스는 유형 목록 (필드라고 함)의 각 유형에 대해 배열을 할당하고 이러한 버퍼에 불투명 포인터를 저장합니다. typesafe getter는 특정 필드 인덱스에 액세스하기 위해 구현됩니다. 그것의 구현은 다음과 같다 :
// container class, stores an array for each type in the typelist
template<class TL>
class Volume {
public:
// list of opaque buffers
void *opaque_buffers[TLAlg::length<TL>::value];
template<int size>
Volume(const size_t (&dim)[size]){
// each opaque_buffers is initialized here
...
}
// getters are using the field index for type-safety
template <int index> typename
TLAlg::TypeAt<TL, index>::Result &
get(const std::initializer_list<size_t> &position);
};
우리는 typelist의 특정 부분 집합을 사용하여 볼륨에 주어진 함수를 적용하는 Functor
객체를 구현하려는. 배열을 직접 조작하는 대신 사용자는 액세스하려는 필드의 인덱스 목록과 적용 할 함수의 포인터를 제공합니다. Functor 객체는 올바른 인수를 설정해야합니다.
const
하지
const
을 읽기) 참조하십시오. 주어진 함수 프로토 타입은 functor 오브젝트의 정의와 일치해야합니다. 주어진 함수 포인터가 인수 정의와 정확히 일치하는 경우에만 코드가 컴파일되므로 불일치 유형에 대해 걱정할 필요가 없습니다. 펑터의 구현은 다음과 같습니다 당신이 볼 수 있듯이 나는 용기 어레이에 두 개의 매개 변수 팩을지도하고 결합하는 방법을 모르기 때문에
template<typename TL, class T1, class T2> struct Functor{};
template< typename TL,
template<size_t...> class T1, size_t... A1, // read only arguments
template<size_t...> class T2, size_t... A2 // read-write arguments
>
struct Functor< TL, T1<A1...>, T2<A2...> >{
// type of the function pointer
typedef void (*Type)(const typename TLAlg::TypeAt<TL, A1>::Result* ... ,
typename TLAlg::TypeAt<TL, A2>::Result* ...);
Functor(Volume<TL> &v, Type f): f(f){
// At this point we have everything we need: the volume, the function
// and the list of arguments, but how to combine them all?
// maybe some magic here to map the opaque pointers to the arguments?
}
void operator()(){
// or maybe here?
}
}
은 펑은 지금 아무것도하지 않습니다 함수 포인터에 ...
명확성을 위해, 여기에 펑터 클래스에 대한 사용의 예입니다
// main Typelist
typedef Typelist<float, Typelist<double, Typelist<int, NullType>>> Pixel;
// function we want to apply: reads first and last field of the list and updates second
void foo(const float *f1,
const int *f3,
double *f2){}
// helper class to store the parameter packs
template<size_t ... T> struct Pack {};
int main(){
// volume declaration
Volume<Pixel> volume((size[]){1024,1024});
// delare typesafe functor
Functor<Pixel, // typelist
Pack<0,2>, // list of read-only fields
Pack<1> // list of read-write fields
> apply_foo(volume, foo);
apply_foo(); // <- this does nothing at the moment
}
나는 오랜 시간 동안 std::forward
및 std::bind
와 함께 연주 시도는,하지만 난 얻을 수 없다 아직 올바른 해결책은 아닙니다. 유형 목록을 std::tuple
으로 대체하는 것이 고려 될 수 있지만 현재 정의를 유지하는 것이 바람직합니다.
이 코드는 이상하고 불필요하게 복잡해 보일지 모르지만 이러한 클래스를 사용하는 것이 막대한 프레임 워크의 매우 단순화 된 버전입니다.
도움을 주시면 감사하겠습니다.Yakk의 답변
부연 설명 :
나는리스트의 각 요소는 튜플 대신 이름을 연결하는 하나의 유형이 될 수 있습니다 예를 들어, 그것은 더 마법을하고있는 중이 야하기 때문에 나는 typelist 필요합니까. 이를 통해 같은 깔끔한 코드 :이 내가 펑터와 구현하려는 작업의 종류에 아주 잘 결합하는 방법을 당신이 상상할 수있는
typedef MakeTypeList((float, p),
(float, bnd),
(float, gosa)) HimenoFields;
// I can now use aliases, and the declaration order does not matter in the code.
// here is an access to the second field:
volume.get<HimenoFields::bnd>({0,0,0});
.
둘째로, 나는 왜 당신이 getter에 혼란스러워하는지 이해합니다. 제가 처음에 말했듯이 이것은 아주 긴 질문에도 불구하고 코드의 매우 단순화 된 버전입니다. 실제 프로그램에서 볼륨은 다차원이며 단일 배열에서 병합되거나 다차원 배열로 할당되므로 getter가 완전한 좌표를 필요로합니다. 이러한 getter에는 여러 가지 매개 변수가있는 여러 구현이 있습니다.
마지막으로 Functor는 반복 영역을 제어하고 사전 정의 된 스켈레톤 (예 : 스텐실, 웨이브 프론트 ...)을 적용하기 때문에 함수를 적용 할 요소를 알 필요가 없습니다. 다시 간단히하기 위해 생략했습니다. variardic 유형 대신하여 18 인수 해킹과
template<typename... Ts>
struct type_list {};
:
TL TR 꽤 있습니다! –
내가 틀렸다면 정정 해주세요.하지만'Functor, Pack <1>> :: Type'은'foo'의 서명과 아주 유사하지 않습니다. 'std :: tuple'을 타입리스트로 즉석에서 볼 때, 당신은 [GCC가 그 주제에 관해 무엇을 말하고 있는지] 볼 수 있습니다 (http://coliru.stacked-crooked.com/view?id=d1ce87766f03b88b3494d6e77dae58fc-50d9cfc8a1d350e7409e81e87c2653ba). –
글쎄, 내 잘못을 발견했다. 인수를 다시 셔플 할 수있는 코드가 더있어 사본 복사에 너무 빠르다. const는 내가 준 예제에서 함께 포장됩니다. 그에 따라'foo'를 편집했습니다. – Thibaut