함수를 가져 와서 아래와 같이 함수 서명을 기반으로 실행하는 코드가 있습니다.
template <int Num>
struct Value {
int value[Num];
};
struct Executor {
template <int N>
void do_exec(std::vector<Value<N>>& n, void (&func) (Value<N>&)) {
for (auto& item : n)
func(item);
}
template <int N>
void do_exec(std::vector<Value<N>>& n, void (&func) (Value<N>&, int)) {
for (int i = 0; i != n.size(); i++)
func(n[i], i);
}
};
사용자가 다음 함수 중 하나를 전달 하면 서명과 일치하는를 Executor
실행합니다 do_exec()
.
template <int N>
void f1(Value<N>& item)
{
for (auto& i : item.value) {
i = 123;
}
}
template <int N>
void f2(Value<N>& item, int d)
{
for (auto& i : item.value) {
i = d;
}
}
int main()
{
Executor exec;
std::vector<Value<3>> vec(10);
exec.do_exec(vec, f1);
}
실제 코드에서는 거의 모든 에이전트가이를 GENERIC 람다로 호출하므로이 코드를 확장하여 람다 함수를 사용할 수 있습니다.
펑터를으로 바꾸려고했지만 std::function
람다가 아니고 std::function
유형 추론이 실제로 발생하지 않았기 때문에 실패했습니다 .
그런 다음 두 개의 템플릿 인수와 SFINAE를 아래와 같이 서명과 일치하지 않는 인수를 가져 오려고했습니다.
template <typename Fn, typename T, typename = void>
struct HasIndex : std::false_type {};
template <typename Fn, typename T>
struct HasIndex<Fn, T, std::void_t<std::invoke_result_t<Fn, T&, int>>> : std::true_type {};
struct Executor {
template <int N, typename Fn, std::enable_if_t<!HasIndex<Fn, Value<N>>::value, int> = 1>
void do_exec(std::vector<Value<N>>& n, Fn func) {
for (auto& item : n)
func(item);
}
template <int N, typename Fn, std::enable_if_t<HasIndex<Fn, Value<N>>::value, int> = 1>
void do_exec(std::vector<Value<N>>& n, Fn func) {
for (int i = 0; i != n.size(); i++)
func(n[i], i);
}
};
실행자가 취할 함수는 항상 템플릿 함수 (GENERIC Lambda)이기 때문에 이것도 작동하지 않았습니다. 이 문제에 접근하는 방법을 정확히 모르겠습니다. 어떤 도움을 주시면 감사하겠습니다.
C ++ 14 해결책을주십시오 (invoke_result가 C ++ 17이라는 것을 알고 있습니다)
수정은 매우 간단합니다. 첫째, std::is_invocable_v
SFINAE 메커니즘에서 호환 가능한 함수 서명을 테스트하기 위해 유형 특성 라이브러리에서 사용합니다. 줄 바꿈은 템플릿 서명을 읽기 쉽게 유지합니다.
template<
int N,
typename Fn,
std::enable_if_t<std::is_invocable_v<Fn, Value<N>&>>* = nullptr
>
void do_exec(std::vector<Value<N>>& n, Fn func) {
[...]
}
template<
int N,
typename Fn,
std::enable_if_t<std::is_invocable_v<Fn, Value<N>&, int>>* = nullptr
>
void do_exec(std::vector<Value<N>>& n, Fn func) {
[...]
}
이렇게하면 함수 및 일반 람다에 대한 템플릿이 아닌 참조가 허용되지만 다음은 아직 작동하지 않습니다.
template <int N>
void f1(Value<N>& item){ [...] }
int main(){
Executor exec;
std::vector<Value<3>> vec(10);
exec.do_exec(vec, f1);
}
나를 위해 이것은 꽤 일반적인 템플릿 인수 추론 / 대체 실패로 실패합니다. 이 작업을 수행하려면 다음 f1
과 같이에 대한 값 으로 전문화해야합니다 N
.
int main(){
Executor exec;
std::vector<Value<3>> vec(10);
exec.do_exec(vec, f1<3>); // Fn is deduced as void(&)(Value<3>&) (I think)
}
C ++ 14 호환성 업데이트
때문에 std::is_invocable_v
C ++ 17 일 이후에만 가능하며, 다음과 같이 당신은 해결 방법을 사용할 수 있습니다 (철저하게 테스트하지,하지만 난 그것에 대해 좋은 느낌)
template<typename F, typename ArgsTuple, typename Enable = void>
struct my_is_invocable_impl : std::false_type {};
template<typename F, typename... Args>
struct my_is_invocable_impl<
F,
std::tuple<Args...>,
decltype(std::declval<F>()(std::declval<Args>()...))
> : std::true_type {};
template<typename T, typename... Args>
constexpr bool my_is_invocable = my_is_invocable_impl<T, std::tuple<Args...>>::value;
// Some test cases
static_assert(my_is_invocable<void(*)(int, double), int, double>, "Oops");
static_assert(my_is_invocable<void(*)(void*), void*>, "Oops");
static_assert(my_is_invocable<void(*)()>, "Oops");
static_assert(!my_is_invocable<void(*)(int, double)>, "Oops");
static_assert(!my_is_invocable<void(*)(void*)>, "Oops");
이는 std::is_invocable_v
위의 솔루션에서 드롭 인 교체로 사용할 수 있습니다 . 일반 람다를 포함한 전체 예제는 데모를 참조하십시오.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다