불변성에 관계없이 포인터-메소드를 취하는 함수
개체에 대한 참조와 해당 멤버 함수에 대한 포인터를 가져와 호출하는 일반 함수를 구현하고 싶습니다. 그러나 두 개의 오버로드를 제공해야하므로 내 클래스에 const 및 non-const 메서드가 모두있을 때 그렇게 할 수 없습니다.
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...))
{
return (object.*method)(Us{}...);
}
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...) const)
{
return (object.*method)(Us{}...);
}
const 및 non-const 메서드 포인터를 모두 허용하는 템플릿 함수를 하나만 작성하는 방법이 있으므로 코드를 두 번 작성할 필요가 없습니까? C ++ 14를 사용하고 있습니다.
더 넓은 그림을 위해 궁극적으로 달성하고자하는 것은 메서드 인수가 추출되는 데이터 버퍼 인 세 번째 매개 변수를 전달하는 것입니다. 따라서 가능한 한 일반적으로이를 처리하는 템플릿 함수입니다.
답변
다음은 std::function
.
내가 궁극적으로 달성하고 싶은 것은 메서드 인수가 추출되는 데이터 버퍼 인 세 번째 매개 변수를 전달하는 것입니다. 따라서 가능한 한 일반적으로이를 처리하는 템플릿 함수
통화 사이트에서 사용하는 내용은 여기에 완벽하게 전달됩니다.
template<typename Class, typename Func, typename... Args>
decltype(auto) callMethod_impl(Class& object, Func method, Args&&... args) {
return (object.*method)(std::forward<Args>(args)...);
}
template<typename Ret, typename Class, typename... Us, typename... Args>
Ret callMethod(Class& object, Ret(Class::*method)(Us...), Args&&... args) {
return callMethod_impl(object, method, std::forward<Args>(args)...);
}
template<typename Ret, typename Class, typename... Us, typename... Args>
Ret callMethod(const Class& object, Ret(Class::*method)(Us...) const, Args&&... args) {
return callMethod_impl(object, method, std::forward<Args>(args)...);
}
데모
Ret
에서 필요한 경우 callMethod_impl
템플릿 매개 변수로 추가 callMethod_impl<Ret>(...)
하고 callMethod
오버로드 ( Demo ) 에서처럼 호출합니다 .
짧은 대답은 직접 구현하지 마십시오. 이미 다음과 같은 형식으로 수행되었습니다 std::invoke.
#include <functional>
struct A {
void foo(int x);
void bar(int x) const;
};
void example() {
A a;
std::invoke(&A::foo, a, 3);
std::invoke(&A::bar, a, 3);
}
돌이켜 보면 C ++ 14 태그를 추가했음을 확인한 후의 문서에 std::invoke프로젝트에서 사용할 수있는 샘플 구현이 있습니다.
를 사용하지 않으면 std::invoke
유형 삭제에 따라 다소 일반적인 해결 방법 만 수행 할 수 있습니다. 를 사용 std::function
하면 동일한 기반에서 함수를 처리하는 프록시 함수를 만들 수 있습니다.
#include <iostream>
#include <functional>
template<typename Ret, typename ...Us>
Ret callMethod_impl(std::function<Ret(Us...)> f) {
// common implementation here
return f(Us{}...);
}
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...)) {
return callMethod_impl(std::function<Ret(Us...)>(std::bind(method, object)));
}
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(const Class &object, Ret (Class::*method)(Us...) const) {
return callMethod_impl(std::function<Ret(Us...)>(std::bind(method, object)));
}
struct Foo {
int bar() const { return 1; }
float bar() { return 2.1f; };
};
int main() {
Foo f;
std::cout << callMethod(f, &Foo::bar) << std::endl;
}
참고 것으로 volatile
기능 (+ 조합) 여기에 처리되지 않은,하지만 어쩌면 당신은 전체 일반성이 아니라 실용적인 솔루션을 필요로하지 않습니다.