struct Point
{
int x;
int y;
};
int main()
{
int Point::*p2 = &Point::y;
}
p2는 Point 구조체 안에서 y의 offset(4)을 담고 있음 (int는 4byte이므로)
int main()
{
...
// *p2 = 10; // error, p2를 바로 쓸 순 없음
Point pt;
pt.*p2 = 10; // pt.y = 10
// *((char*)&pt + p2) = 10; // pt의 주소에서 p2의 오프셋만큼 더하여 접근
cout << p2 << std::endl; // 1 cout은 이상하게 나옴
printf("%p\n", p2); // 4
}
int main()
{
int Point::*p = &Point::y;
Point obj;
obj.*p = 10; // obj.y = 10
(&obj)->*p = 10;
std::invoke(p, obj) = 20; // obj.y = 20
int n = std::invoke(p, obj);
std::cout << n << std::endl;
std::cout << obj.y << std::endl;
}
Callable Type: std::invoke()를 사용할 수 있는 타입
std::invoke()에 멤버 함수 포인터 뿐만 아니라 멤버 데이터 포인터도 넣을 수 있음
문자열의 크기 비교
template<class T>
const T& mymax(const T& obj1, const T& obj2)
{
return obj1 < obj2 ? obj2 : obj1;
}
int main()
{
std::string s1 = "abcd";
std::string s2 = "xyz";
auto ret = mymax(s1, s2); // "xyz"
}
auto ret = mymax(s1, s2, [](auto& a, auto& b) { return a.size() < b.size(); } );
auto ret = mymax(s1, s2, [](auto& a) { return a.size(); } ); // f(s1) < f(s2)
#include <functional>
template<class T, class Proj>
const T& mymax(const T& obj1, const T& obj2, Proj proj)
{
// return proj(obj1) < proj(obj2) ? obj2 : obj1;
// (obj2.*proj)() // 이러면 멤버 함수 포인터만 가능
return std::invoke(proj, obj1) < std::invoke(proj, obj2) ? obj2 : obj1;
}
int main()
{
std::string s1 = "abcd";
std::string s2 = "xyz";
auto ret1 = mymax(s1, s2, [](auto& a) { return a.size(); } ); // 단항 조건자
auto ret2 = mymax(s1, s2, &std::string::size); // 멤버 함수 포인터 전달
}
template<class T, class Proj = std::identity>
const T& mymax(const T& obj1, const T& obj2, Proj proj = {} )
{
// proj 인자가 없다면 Proj 타입을 std::identity로 만들고
// proj는 std::identity의 디폴트 객체로 생성
return std::invoke(proj, obj1) < std::invoke(proj, obj2) ? obj2 : obj1;
}
int main()
{
std::string s1 = "abcd";
std::string s2 = "xyz";
auto ret = mymax(s1, s2);
}
std::identity(): 전달받은 인자를 어떠한 변화도 없이 그대로 반환하는 함수객체 (C++20)
struct Point
{
int x, y;
};
int main()
{
Point p1 = {2, 0};
Point p2 = {1, 1};
auto ret = mymax(p1, p2, &Point::y); // y값으로 비교
}
mymax() 함수의 std::invoke(proj, obj1)에서 멤버 변수 포인터를 사용하면 (obj1.*proj)로 동작
template<class T, class Comp = std::less<void>, class Proj = std::identity>
const T& mymax(const T& obj1, const T& obj2, Comp comp = {}, Proj proj = {})
{
// return std::invoke(proj, obj1) < std::invoke(proj, obj2) ? obj2 : obj1;
// return comp(std::invoke(proj, obj1), std::invoke(proj, obj2)) ? obj2 : obj1; // 멤버함수일 땐 에러발생하여 invoke로 감싸기
return std::invoke(comp, std::invoke(proj, obj1), std::invoke(proj, obj2)) ? obj2 : obj1;
}
int main()
{
std::string s1 = "abcd";
std::string s2 = "xyz";
auto ret1 = mymax(s1, s2); // 객체만 전달
auto ret2 = mymax(s1, s2, std::greater{}); // 비교 함수객체 전달
auto ret3 = mymax(s1, s2, {}, &std::string::size); // projection 전달
auto ret4 = mymax(s1, s2, std::greater{}, &std::string::size); // 비교 함수객체, projection 모두 전달
}
auto ret = std::ranges::max(s1, s2, std::ranges::greater{}, &std::string::size);
std::range::max는 함수 객체(템플릿)
반복자 구간이 아닌 컨테이너를 전달받음
std::vector<std::string> v = { "hello", "a", "xxx", "zz" };
// std::sort(v.begin(), v.end());
// std::ranges::sort(v);
std::ranges::sort(v, std::ranges::greater{}, &std::string::size);