카테고리 없음

C++23 : Deducing this

Sorting 2022. 12. 18. 18:01
반응형

 

 

 

visual studio 2022 에 구현된 C++ 기능들을 하나씩 알아가다보면

왜 이게 이제서야 생겼나 싶을 때가 있다.

 

deducing this 문법 역시 이러한 느낌이 든다.

이 생소한 이름의 feature는 무엇이며 언제, 왜 쓰는 것일까?

 

아래와 같은 상황을 생각해보자.

 

#include<iostream>

class Test
{
public:
	int& value() { return v; }

private:
	int v = 0;
};

int main()
{
	const Test t;
	std::cout << t.value() << std::endl;
}

 

Test 라는 클래스에는 멤버를 접근할 수 있는 value() 라는 함수가 존재한다.

그러나 이 함수는 내부적으로 멤버를 수정 가능하기 때문에,

실제로 해당 함수로 값을 수정하려고 했는지와는 상관 없이

t객체가 const 인 상황에서는 value() 함수를 호출할 수 없다.

 

이런 경우 C++에서의 전통적인 해결방법은,

바로 다음과 같이 멤버를 수정할 수 없는 버전의 함수를 하나 더 선언하는 것이다.

 

#include<iostream>

class Test
{
public:
	int& value() { return v; }
	const int& value() const { return v; }

private:
	int v = 0;
};

int main()
{
	const Test t;
	std::cout << t.value() << std::endl;
}

 

이러한 상황을 지금껏 만나오면서

'그래 C++이란 원래 이런것이니까' 라고 생각해왔다.

그런데 꼭 이래야만 했을까? 

 

고맙게도 아래 프로포절을 통해 deducing this 라는 feature 가 c++23에 도입되었고,

이 기능이 위 현상을 해결할 수 있게 해준다.

 

Deducing this

template class optional { // ... template constexpr auto and_then(F&& f) & { using result = invoke_result_t ; static_assert( is_optional ::value, "F must return an optional"); return has_value() ? invoke(forward (f), **this) : nullopt; } template constexpr

www.open-std.org

 

위 feature 를 사용한 솔루션은 다음과 같다.

#include<iostream>

class Test2
{
public:
	template<class Self>
	auto&& value(this Self&& self) { return self.v; }

private:
	int v = 0;
};

int main()
{
	const Test2 t2;
	std::cout << t2.value() << std::endl;
}

아주 깔끔하다.

파이썬에서 멤버 메소드 정의부 첫번째 파라미터로 self 를 써넣듯,

함수 내부에서는 알 수 없던 this의 상태를 외부에서 주입해옴으로써 문제를 해결할 수 있다.

 

이 feature 를 사용하면, 내부적으로 자기자신을 호출할 이름이 없어서 구현이 어려웠던

람다 재귀함수 역시 다음과 같이 간단하게 표현이 가능하다.

 

auto fibonacci = [](this const auto& self, int n) -> long {
		return n < 2 ? n : self(n - 1) + self(n - 2);
	};

참고 : https://www.dev0notes.com/intermediate/recursive_lambdas.html

반응형