n차원 배열 포인터를 리턴하는 함수에 대한 함수포인터 작성법

#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하면 됩니다.

따라서 배열을 다룰 때는 위와같이 사용할 수도 있음을 알 수 있었습니다.