#include <iostream>
#include <iomanip>
#include <string>
#include <locale>
#include <numeric>
#include <vector>
#include <ranges>
#include <tchar.h>
#define fst 3
#define sec 3
#define thd 3
#define fth 3
template <typename T>
using Array3D = T[sec][thd];
template <typename T>
using Array3DPtr = Array3D<T>*;
template <typename T>
T(*someF(T))[sec][thd][fth];
template <typename T>
T (*Tunc())[sec][thd][fth]
{
T(*Temp)[sec][thd][fth] = new T[fst][sec][thd][fth];
int count = 1;
for (auto i : std::views::iota(0, fst))
{
for (auto j : std::views::iota(0, sec))
{
for (auto k : std::views::iota(0, thd))
{
for (auto l : std::views::iota(0, fth))
{
*(*(*(*(Temp + i) + j) + k) + l) = count++;
}
}
}
}
for (auto i : std::views::iota(0, fst))
{
for (auto j : std::views::iota(0, sec))
{
for (auto k : std::views::iota(0, thd))
{
for (auto l : std::views::iota(0, fth))
{
std::cout << *(*(*(*(Temp + i) + j) + k) + l) << std::setw(5);
}
}
}
}
std::cout << std::endl;
return Temp;
}
int (*func())[sec][thd]
{
//incrementing sequence of values or initialization fo a contiguous range with increasing values
std::vector<int> numbers(fst);
std::iota(numbers.begin(), numbers.end(), 0);
int (*Arr)[sec][thd] = new int[fst][sec][thd];
int count = 1;
for (int i = 0; i < fst; i++) {
for (int j = 0; j < sec; j++)
{
for (int k = 0; k < thd; k++)
{
*(*(*(Arr + i) + j) + k) = count++;
}
}
}
for (int i = 0; i < fst; i++) {
for (int j = 0; j < sec; j++)
{
for (int k = 0; k < thd; k++)
{
std::cout << *(*(*(Arr + i) + j) + k) << std::setw(5);
}
}
}
std::cout << std::endl;
return Arr;
}
int* f3(){
int* ptr = new int[1];
*ptr = 100;
return ptr;
}
void test()
{
std::cout << "hello world!" << std::endl;
}
int (*hamsu())[2]
{
int (*r)[2] = new int[1][2];
r[0][0] = 1000;
r[0][1] = 2000;
return r;
}
int main(int argc, char* argv[])
{
std::locale::global(std::locale(""));
std::wcout.imbue(std::locale());
std::wcin.imbue(std::locale());
int (*ptr)[sec][thd] = func();
std::cout << "\b";
std::cout << std::endl;
Array3DPtr<int>(*fp)() = func;
std::cout << "start\b" << std::endl;
int (*(*fps)())[sec][thd];
fps = func;
fps();
std::cout << "end\b" << std::endl;
for (auto i : std::views::iota(0, fst))
{
for (auto j : std::views::iota(0, sec))
{
for (auto k : std::views::iota(0, thd))
{
std::cout << *(*(*(ptr + i) + j) + k) << std::setw(5);
}
}
}
std::cout << std::endl;
std::cout << "\b" << std::endl;
//auto (*Tempu)[sec][thd][fth] = Tunc<int>();
//int (*(*fps)())[sec][thd];
double (*(*sexyPtr[2][2])())[sec][thd][fth];
using sexyPtr_element_type = double(*(*)())[sec][thd][fth];
sexyPtr_element_type(*goodPtr)[2][2] = &sexyPtr;
double (*(*(*goodPtr2)[2][2])())[sec][thd][fth] = &sexyPtr;
/*
* 배열 포인터를 반환하는 함수를 가르키는 함수포인터에 대한 배열포인터를 가르키는 함수포인터들의 배열
*/
auto lambda_someF_double1 = []() -> double(*)[sec][thd][fth]
{
return someF(2.71);
};
auto lambda_someF_double2 = []() -> double(*)[sec][thd][fth]
{
return someF(3.14);
};
sexyPtr[0][0] = lambda_someF_double1;
sexyPtr[0][1] = lambda_someF_double2;
double(*result_ptr)[sec][thd][fth] = (*goodPtr)[0][0]();
double(*result_ptr2)[sec][thd][fth] = (*goodPtr2)[0][0]();
std::cout << "First element of returned array: " << (*result_ptr2)[0][0][0] << std::endl;
std::cout << "First element of returned array: " << (*result_ptr)[0][0][0] << std::endl;
std::cout << "\b" << "";
sexyPtr[0][0]();
std::cout << "\b" << std::endl;
sexyPtr[0][1]();
std::cout << "\b" << "";
//delete[] Tempu;
delete[] ptr;
return EXIT_SUCCESS;
}
template <typename T>
T (*someF(T value))[sec][thd][fth]
{
T(*temp)[sec][thd][fth] = new T[fst][sec][thd][fth];
for (auto i : std::views::iota(0, fst))
{
for (auto j : std::views::iota(0, sec))
{
for (auto k : std::views::iota(0, thd))
{
for (auto l : std::views::iota(0, fth))
{
*(*(*(*(temp + i) + j) + k) + l) = value;
}
}
}
}
for (auto i : std::views::iota(0, fst))
{
for (auto j : std::views::iota(0, sec))
{
for (auto k : std::views::iota(0, thd))
{
for (auto l : std::views::iota(0, fth))
{
std::cout << *(*(*(*(temp + i) + j) + k) + l) << std::setw(5);
}
}
}
}
std::cout << "\b" << std::endl;
return temp;
}
우선 전체 코드입니다.
template <typename T>
T(someF(T value))[sec][thd][fth] { T(temp)[sec][thd][fth] = new T[fst][sec][thd][fth];
for (auto i : std::views::iota(0, fst))
{
for (auto j : std::views::iota(0, sec))
{
for (auto k : std::views::iota(0, thd))
{
for (auto l : std::views::iota(0, fth))
{
*(*(*(*(temp + i) + j) + k) + l) = value;
}
}
}
}
for (auto i : std::views::iota(0, fst))
{
for (auto j : std::views::iota(0, sec))
{
for (auto k : std::views::iota(0, thd))
{
for (auto l : std::views::iota(0, fth))
{
std::cout << *(*(*(*(temp + i) + j) + k) + l) << std::setw(5);
}
}
}
}
std::cout << "\b" << std::endl;
return temp;
}
라는 코드가 있다고 가정합니다. c++ 20버전 이상에서 컴파일 되는 코드입니다. 이 함수는 4차원 배열에 대한 배열 포인터를 반환합니다. 이 배열 포인터를 어떻게 다른 함수에서 받을 수 있을까요?
auto lambda_someF_double1 = []() -> double(*)[sec][thd][fth]
{
return someF(2.71);
};
auto lambda_someF_double2 = []() -> double(*)[sec][thd][fth]
{
return someF(3.14);
};
우선 첫번째 방법으로는 람다식과 타입 추론 (auto)를 사용하여 람다식의 []로 함수를 캡쳐하고 ()로 인수를 받아들이는 방식으로 받을 수 있겠습니다.
위와 같이 람다식으로 받았으면
함수 포인터 배열을 만들어서 람다함수를 가르키는 배열로 여러 배열을 가리킬 수 있겠습니다.
double (*(*sexyPtr[2][2])())[sec][thd][fth];
using sexyPtr_element_type = double(*(*)())[sec][thd][fth];
sexyPtr_element_type(*goodPtr)[2][2] = &sexyPtr;
double (*(*(*goodPtr2)[2][2])())[sec][thd][fth] = &sexyPtr;
/*
* 배열 포인터를 반환하는 함수를 가르키는 함수포인터에 대한 배열포인터를 가르키는 함수포인터들의 배열
*/
auto lambda_someF_double1 = []() -> double(*)[sec][thd][fth]
{
return someF(2.71);
};
auto lambda_someF_double2 = []() -> double(*)[sec][thd][fth]
{
return someF(3.14);
};
sexyPtr[0][0] = lambda_someF_double1;
sexyPtr[0][1] = lambda_someF_double2;
double(*result_ptr)[sec][thd][fth] = (*goodPtr)[0][0]();
double(*result_ptr2)[sec][thd][fth] = (*goodPtr2)[0][0]();
std::cout << “First element of returned array: ” << (result_ptr2)[0][0][0] << std::endl; std::cout << “First element of returned array: ” << (result_ptr)[0][0][0] << std::endl;
std::cout << “\b” << “”;
sexyPtr[0][0]();
std::cout << “\b” << std::endl;
sexyPtr[0][1]();
…
와 같이 사용할 수 있겠고…
int (*func())[sec][thd]
{
//incrementing sequence of values or initialization fo a contiguous range with increasing values
std::vector<int> numbers(fst);
std::iota(numbers.begin(), numbers.end(), 0);
int (*Arr)[sec][thd] = new int[fst][sec][thd];
int count = 1;
for (int i = 0; i < fst; i++) {
for (int j = 0; j < sec; j++)
{
for (int k = 0; k < thd; k++)
{
*(*(*(Arr + i) + j) + k) = count++;
}
}
}
for (int i = 0; i < fst; i++) {
for (int j = 0; j < sec; j++)
{
for (int k = 0; k < thd; k++)
{
std::cout << *(*(*(Arr + i) + j) + k) << std::setw(5);
}
}
}
std::cout << std::endl;
return Arr;
}
3차원 배열포인터 반환함수를 예로 들면…
int main(int argc, char* argv[])
{
std::locale::global(std::locale(""));
std::wcout.imbue(std::locale());
std::wcin.imbue(std::locale());
int (*ptr)[sec][thd] = func();
std::cout << "\b";
std::cout << std::endl;
}
와 같이 받아들일 수 있겠습니다. 참고로 위의 locale코드는 c++에서 유니코드를 사용하기 위함입니다. MSVC는 utf16을 기본 유니코드로 사용하는데 아무래도 로케일이 기본적으로 한국어로 설정되어 있지 않은면이 있습니다. 따라서 위의 코드 세 줄을 추가하면 사용자의 시스템 로케일에 맞춰 로케일을 설정해주기에 한국어를 출력하는게 가능해집니다.
위와 같이 배열포인터를 받을 수 있게 배열포인터의 반환타입에 맞춰 포인터를 짜고 그에 맞춰 assign하면 됩니다.
따라서 배열을 다룰 때는 위와같이 사용할 수도 있음을 알 수 있었습니다.