기본적으로,내가 무엇을 달성하고 싶은 컴파일시 확인(아마도 좋은 오류 메시지가)등록 가능(하나의 기능,람다,구조체와의 전화 연산자)가 정확한 서명이 있습니다. 예(의 내용을말고 static_assert
을 가득):
struct A {
using Signature = void(int, double);
template <typename Callable>
void Register(Callable &&callable) {
static_assert(/* ... */);
callback = callable;
}
std::function<Signature> callback;
};
당신이 사용할 수 있std::is_convertible(기 때문 C++11),예를 들어,
static_assert(std::is_convertible_v<Callable&&, std::function<Signature>>, "Wrong Signature!");
나
static_assert(std::is_convertible_v<decltype(callable), decltype(callback)>, "Wrong Signature!");
대부분의 답변에 초점을 맞추고 있는 기본적으로 질문에 대답할 수 있**전화된 함수 개체의 값으로 이러한 유형입니다. 이것은 동일하지 않으로 일치하는 서명할 수 있어 많은 암시적 변환을 말하지't 니다. 을 얻기 위해 더 엄격한 경 우리는 우리 무리의 TMP. 첫째,이 대답:https://stackoverflow.com/questions/46014058/call-function-with-part-of-variadic-arguments/46014785#46014785 을 가져오는 방법을 보여 줍니다 정확한 형태의 인수 및 반환한 유형의 호출 가능. 코드 재생기:
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
using result_type = ReturnType;
using arg_tuple = std::tuple<Args...>;
static constexpr auto arity = sizeof...(Args);
};
template <typename R, typename ... Args>
struct function_traits<R(&)(Args...)>
{
using result_type = R;
using arg_tuple = std::tuple<Args...>;
static constexpr auto arity = sizeof...(Args);
};
가 수행하는,당신은 지금 일련의 정적 주장에서 당신의 코드:
struct A {
using Signature = void(int, double);
template <typename Callable>
void Register(Callable &&callable) {
using ft = function_traits<Callable>;
static_assert(std::is_same<int,
std::decay_t<std::tuple_element_t<0, typename ft::arg_tuple>>>::value, "");
static_assert(std::is_same<double,
std::decay_t<std::tuple_element_t<1, typename ft::arg_tuple>>>::value, "");
static_assert(std::is_same<void,
std::decay_t<typename ft::result_type>>::value, "");
callback = callable;
}
std::function<Signature> callback;
};
이후에 의해 전달되는 값이 기본적으로 모든 당신이 필요합니다. 전달하는 경우에는 참조를 통해,나는 추가 정 주장하는 곳 중 하나를 사용하여 다른 답변;아마 songyuanyao's answer. 이의 개인정보는 법률에 의한 경우가 어디 예를 들어 기본 형식이 동일하지만,const 자격 잘못된 방향으로 갔다.
수은 물론 이 모든 일반적인 유형 서명한 대신의 일을 내가 무엇(단순히 반복되는 종류에 정적 assert). 이 될 것이 더 좋지만 그것도 추가 더 복잡한 TMP 이미 아닌 사소한 대답을 느낄 경우처럼 당신이 사용하는 이는 많은 다른 서명 또는 변화는 종종 아마도 가치를 추가하는 코드뿐만 아니라.
여기's live 를 들어:http://coliru.stacked-crooked.com/a/cee084dce9e8dc09. 특히,내 예를 들어:
void foo(int, double) {}
void foo2(double, double) {}
int main()
{
A a;
// compiles
a.Register([] (int, double) {});
// doesn't
//a.Register([] (int, double) { return true; });
// works
a.Register(foo);
// doesn't
//a.Register(foo2);
}
에서는 C++17 있 특성is_invocable<호출 가능,Args...된다
는 정확히 무엇을 부탁드립니다. 그것의 이점을 통해is_convertible<std::function<서>...>
은 당신이't 를 지정해야익 유형입니다.
그것도 같은 소리를 과도 하지만 최근에 문제가 있었던 그것을 사용하려면,정확히 내 래퍼 함수 추론 그 반환을 입력에서 전달되는 경우 호출 가능하지만,나는've 전달되는 템플릿 람다 이 같은[](auto&x){return2*x;}
,그 반환의 유형이었다는 추론에서 subcall. 나't 로 변환std::함수는
나는 끝까지 사용하여 지역의 구현is_invocable
를 위한 C++14. 을 찾을 수 없습니다 링크를 내가 가지고 어디에서긴 하지만 어쨌든,코드:
template <class F, class... Args>
struct is_invocable
{
template <class U>
static auto test(U* p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type());
template <class U>
static auto test(...) -> decltype(std::false_type());
static constexpr bool value = decltype(test<F>(0))::value;
};
과에 대한 예제:
struct A {
using Signature = void(int, double);
template <typename Callable>
void Register(Callable &&callable) {
static_assert(is_invocable<Callable,int,double>::value, "not foo(int,double)");
callback = callable;
}
std::function<Signature> callback;
};
수락할 경우를 변환하는A
에 앞 템플릿 클래스를 사용할 수 있습decltype()
,을 activare등록
는 경우에만호출
호환되는,다음과 같이
template <typename R, typename ... Args>
struct A
{
using Signature = R(Args...);
template <typename Callable>
auto Register (Callable && callable)
-> decltype( callable(std::declval<Args>()...), void() )
{ callback = callable; }
std::function<Signature> callback;
};
이 방법은,당신이 선호하는 경우,전화 등록()
으로 호환되지 않는 기능을,당신은 당신을 얻을 수 있는 소프트웨어 오류를 활성화는 다른 등록()
기능
void Register (...)
{ /* do something else */ };
사용할 수 있습니다 탐지의 관용구,형태의 sfinae. 이 작품에서는 c++11.
template <typename...>
using void_t = void;
template <typename Callable, typename enable=void>
struct callable_the_way_i_want : std::false_type {};
template <typename Callable>
struct callable_the_way_i_want <Callable, void_t <decltype (std::declval <Callable>()(int {},double {}))>> : std::true_type {};
다음 작성할 수 있습니다 정적 주장하는 코드에서는 다음과 같이
static_assert (is_callable_the_way_i_want <Callable>::value, "Not callable with required signature!");
이것의 이점을 통해 답변을 나는 위조은:
-그것은 작동에 대한 모든 가능하지만 람다
-theres 런타임 오버헤드 또는std::함수
사업이다.std::함수
을 일으킬 수 있는 동적 할당,예를 들어,그렇지 않으면 될 것 불필요합니다.
-할 수 있습니다 실제로 쓰기지 말고 static_assert
에 대한 테스트를 넣어 좋은 사용자가 쉽게 이해할 수 있는 오류 메시지가
타탄체크 라마를 썼 블로그 게시물에 대한 이 기술은,그리고 여러 가지 대안을 확인하세요! https://blog.tartanllama.xyz/detection-idiom/
필요하신 경우에는 이렇게 많이 다음을 할 수 있습을 보 callable_traits 라이브러리입니다.