«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Archives
Today
Total
03-28 21:02
관리 메뉴

lancelot.com

가변인자 template 을 이용한 생성자, tag dispatching 을 이용한 생성자 선택 본문

프로그래밍

가변인자 template 을 이용한 생성자, tag dispatching 을 이용한 생성자 선택

lancelot50 2022. 7. 23. 22:38
  • 가변인자 template을 이용한 생성자
#include<iostream>
#include<string>
#include<type_traits>

class Point
{
	int x{ 0 };
	int y{ 0 };
public :
	Point() = default;
	Point(int x, int y) : x(x), y(y) {}
};

template<typename T1, typename T2, bool = std::is_empty_v<T1> > struct compressed_pair;

template<typename T1, typename T2> struct compressed_pair < T1, T2, false>
{
	T1 first;
	T2 second;

	T1& getFirst() { return first; }
	T2& getSecond() { return second; }

	const T1& getFirst() const { return first; }
	const T2& getSecond() const { return second; }

	template<typename A1, typename ... A2>
	compressed_pair(A1&& arg1, A2&& ... arg2) : first(std::forward<A1>(arg1)), second(std::forward<A2>(arg2)...) {}
};

int main()
{
	compressed_pair<int, Point> p1(1, Point(0,0));	// 기본 생성자
	compressed_pair<int, Point> p2(1, 0, 0);		// 가변인자 템플릿을 사용한 생성자
}
  • tag dispatching을 이용한 생성자 선택
#include<iostream>
#include<string>
#include<type_traits>

class Point
{
	int x{ 0 };
	int y{ 0 };
public :
	Point() = default;
	Point(int x, int y) : x(x), y(y) {}
};

class one_and_variadic_arg_t {};
class zero_and_variadic_arg_t {};

template<typename T1, typename T2, bool = std::is_empty_v<T1> > struct compressed_pair;

template<typename T1, typename T2> struct compressed_pair < T1, T2, false>
{
	T1 first;
	T2 second;

	T1& getFirst() { return first; }
	T2& getSecond() { return second; }

	const T1& getFirst() const { return first; }
	const T2& getSecond() const { return second; }

	template<typename A1, typename ... A2>
	compressed_pair(one_and_variadic_arg_t, A1&& arg1, A2&& ... arg2) : first(std::forward<A1>(arg1)), second(std::forward<A2>(arg2)... ) {}

	template<typename ... A2>
	compressed_pair(zero_and_variadic_arg_t, A2&& ... arg2) : first(), second(std::forward<A2>(arg2)... ) {}
};


int main()
{
	compressed_pair<int, Point> p1(one_and_variadic_arg_t{}, 1, Point(0, 0));
	compressed_pair<int, Point> p2(one_and_variadic_arg_t{}, 1, 0, 0);
	compressed_pair<int, Point> p3(zero_and_variadic_arg_t{}, 0, 0);
}

 

  • constexpr : 컴파일시간에 결정가능하다면 그렇게 할 수 있게
  • noexcept 의 조건 설정
#include<iostream>
#include<string>
#include<type_traits>


class Empty { };

struct one_and_variadic_arg_t { explicit one_and_variadic_arg_t() = default; };
struct zero_and_variadic_arg_t { explicit zero_and_variadic_arg_t() = default; };


template<typename T1, typename T2, bool = std::is_empty_v<T1> && !std::is_final_v<T1> > struct compressed_pair;

template<typename T1, typename T2> struct compressed_pair < T1, T2, false>
{
	T1 first;
	T2 second;

	constexpr T1& getFirst() noexcept { return first; }	// 컴파일 시간에 결정되도록
	constexpr T2& getSecond() noexcept { return second; }

	constexpr const T1& getFirst() const noexcept { return first; }
	constexpr const T2& getSecond() const noexcept { return second; }

	template<typename A1, typename ... A2>
	constexpr compressed_pair(one_and_variadic_arg_t, A1&& arg1, A2&& ... arg2)
		noexcept ( // noexcept의 조건 - 멤버의 생성자가 예외를 던지지않음
			std::conjunction_v< std::is_nothrow_constructible<T1, A1>, std::is_nothrow_constructible<T2, A2...> >)
		: first(std::forward<A1>(arg1)), second(std::forward<A2>(arg2)...) {}


	template<typename ... A2>
	constexpr compressed_pair(zero_and_variadic_arg_t, A2&& ... arg2) noexcept(
		std::conjunction_v< std::is_nothrow_default_constructible<T1>, std::is_nothrow_constructible<T2, A2...> >)
		: first(), second(std::forward<A2>(arg2)...) {}
};

// T1 이 empty 인 경우
template<typename T1, typename T2> struct compressed_pair < T1, T2, true> : public T1
{
	T2 second;

	constexpr T1& getFirst() noexcept { return *this; }
	constexpr T2& getSecond() noexcept { return second; }

	constexpr const T1& getFirst() const noexcept { return *this; }
	constexpr const T2& getSecond() const noexcept { return second; }

	template<typename A1, typename ... A2>
	constexpr compressed_pair(one_and_variadic_arg_t, A1&& arg1, A2&& ... arg2)
		noexcept (
			std::conjunction_v< std::is_nothrow_constructible<T1, A1>, std::is_nothrow_constructible<T2, A2...> >)
		: T1(std::forward<A1>(arg1)), second(std::forward<A2>(arg2)...) {}


	template<typename ... A2>
	constexpr compressed_pair(zero_and_variadic_arg_t, A2&& ... arg2) noexcept(
		std::conjunction_v< std::is_nothrow_default_constructible<T1>, std::is_nothrow_constructible<T2, A2...> >)
		: T1(), second(std::forward<A2>(arg2)...) {}
};

int main()
{
	compressed_pair<int, int> cp1 ( one_and_variadic_arg_t{}, 1, 1);
	compressed_pair<Empty, int> cp2 ( zero_and_variadic_arg_t{}, 1);
	compressed_pair<Empty, int> cp3 ( zero_and_variadic_arg_t{});

	std::cout << sizeof(cp1) << std::endl;
	std::cout << sizeof(cp2) << std::endl;
}