템플릿 함수의 함수 서명을 사용하여 SFINAE하는 방법

아프 람

함수를 가져 와서 아래와 같이 함수 서명을 기반으로 실행하는 코드가 있습니다.

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이라는 것을 알고 있습니다)

https://godbolt.org/z/W7z3Mv

늙은 고슴도치

수정은 매우 간단합니다. 첫째, std::is_invocable_vSFINAE 메커니즘에서 호환 가능한 함수 서명을 테스트하기 위해 유형 특성 라이브러리에서 사용합니다. 줄 바꿈은 템플릿 서명을 읽기 쉽게 유지합니다.

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_vC ++ 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위의 솔루션에서 드롭 인 교체로 사용할 수 있습니다 . 일반 람다를 포함한 전체 예제는 데모를 참조하십시오.

C ++ 14 용 라이브 데모

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

Chapel에서 템플릿 함수의 유형 서명을 작성하는 방법

분류에서Dev

템플릿을 템플릿 인수로 사용하는 함수

분류에서Dev

템플릿 클래스 내에서 템플릿 함수의 별칭을 지정하는 방법

분류에서Dev

GDB에서 역 추적의 템플릿 함수 서명을 해석하는 방법은 무엇입니까?

분류에서Dev

템플릿 함수 C ++에서 유형 이름의 서명을 변경하는 방법

분류에서Dev

sfinae와 함께 템플릿 클래스를 사용하는 동안 순수 가상 방법 정의

분류에서Dev

kendoListView 템플릿에서 함수를 호출하는 방법

분류에서Dev

.cpp 파일에서 템플릿 멤버 함수의 명시 적 특수화를 정의하는 방법

분류에서Dev

Django 템플릿의 if 문 내에서 함수를 호출하는 방법

분류에서Dev

C ++에서 공변 템플릿 함수를 정의하는 올바른 방법

분류에서Dev

angularjs의 템플릿에서 컨트롤러 함수를 호출하는 방법

분류에서Dev

가변 템플릿을 사용하여 일반화 된 함수 래퍼를 작성하는 방법

분류에서Dev

템플릿 유형을 함수 매개 변수로 사용하여 추상 템플릿 클래스를 파생하는 방법 (C ++ 11)

분류에서Dev

type_traits 또는 템플릿 함수 전문화를 사용하여 템플릿 메서드를 통합하는 방법

분류에서Dev

클래스 템플릿에서 함수 템플릿을 사용하는 C ++

분류에서Dev

템플릿을 사용하여 멤버 함수를 선언하는 방법은 무엇입니까? (템플릿 클래스가 아님)

분류에서Dev

템플릿 함수에서 mapbox :: util :: variant 값을 검색하는 방법

분류에서Dev

C ++에서 외부 cuda 함수 템플릿을 선언하는 방법

분류에서Dev

템플릿을 사용하여 함수에 유형 보내기

분류에서Dev

C ++ 템플릿을 사용하여 JNI 함수 생성

분류에서Dev

템플릿 클래스에서 템플릿 멤버 함수를 전문화하는 방법 (이미 지정됨)?

분류에서Dev

유형의 문자열을 사용하여 템플릿 함수 호출

분류에서Dev

빈 템플릿에서 변수를 사용하는 방법

분류에서Dev

템플릿 매개 변수 팩을 사용하여 몇 가지 유형으로 제한된 SFINAE를 구현하는 방법

분류에서Dev

파이썬 함수에서 기류 진자 템플릿을 사용하는 방법은 무엇입니까?

분류에서Dev

정적 함수에서 템플릿을 사용하는 방법은 무엇입니까?

분류에서Dev

std :: conditional에서 템플릿을 사용하여 함수 인수 유형 결정

분류에서Dev

템플릿 함수가 매개 변수 팩을 사용할 때 다른 템플릿 매개 변수를 전달하는 방법은 무엇입니까?

분류에서Dev

SASS 함수를 사용하여 (nxn) 그리드의 그리드 영역 템플릿을 동적으로 구축하는 방법

Related 관련 기사

  1. 1

    Chapel에서 템플릿 함수의 유형 서명을 작성하는 방법

  2. 2

    템플릿을 템플릿 인수로 사용하는 함수

  3. 3

    템플릿 클래스 내에서 템플릿 함수의 별칭을 지정하는 방법

  4. 4

    GDB에서 역 추적의 템플릿 함수 서명을 해석하는 방법은 무엇입니까?

  5. 5

    템플릿 함수 C ++에서 유형 이름의 서명을 변경하는 방법

  6. 6

    sfinae와 함께 템플릿 클래스를 사용하는 동안 순수 가상 방법 정의

  7. 7

    kendoListView 템플릿에서 함수를 호출하는 방법

  8. 8

    .cpp 파일에서 템플릿 멤버 함수의 명시 적 특수화를 정의하는 방법

  9. 9

    Django 템플릿의 if 문 내에서 함수를 호출하는 방법

  10. 10

    C ++에서 공변 템플릿 함수를 정의하는 올바른 방법

  11. 11

    angularjs의 템플릿에서 컨트롤러 함수를 호출하는 방법

  12. 12

    가변 템플릿을 사용하여 일반화 된 함수 래퍼를 작성하는 방법

  13. 13

    템플릿 유형을 함수 매개 변수로 사용하여 추상 템플릿 클래스를 파생하는 방법 (C ++ 11)

  14. 14

    type_traits 또는 템플릿 함수 전문화를 사용하여 템플릿 메서드를 통합하는 방법

  15. 15

    클래스 템플릿에서 함수 템플릿을 사용하는 C ++

  16. 16

    템플릿을 사용하여 멤버 함수를 선언하는 방법은 무엇입니까? (템플릿 클래스가 아님)

  17. 17

    템플릿 함수에서 mapbox :: util :: variant 값을 검색하는 방법

  18. 18

    C ++에서 외부 cuda 함수 템플릿을 선언하는 방법

  19. 19

    템플릿을 사용하여 함수에 유형 보내기

  20. 20

    C ++ 템플릿을 사용하여 JNI 함수 생성

  21. 21

    템플릿 클래스에서 템플릿 멤버 함수를 전문화하는 방법 (이미 지정됨)?

  22. 22

    유형의 문자열을 사용하여 템플릿 함수 호출

  23. 23

    빈 템플릿에서 변수를 사용하는 방법

  24. 24

    템플릿 매개 변수 팩을 사용하여 몇 가지 유형으로 제한된 SFINAE를 구현하는 방법

  25. 25

    파이썬 함수에서 기류 진자 템플릿을 사용하는 방법은 무엇입니까?

  26. 26

    정적 함수에서 템플릿을 사용하는 방법은 무엇입니까?

  27. 27

    std :: conditional에서 템플릿을 사용하여 함수 인수 유형 결정

  28. 28

    템플릿 함수가 매개 변수 팩을 사용할 때 다른 템플릿 매개 변수를 전달하는 방법은 무엇입니까?

  29. 29

    SASS 함수를 사용하여 (nxn) 그리드의 그리드 영역 템플릿을 동적으로 구축하는 방법

뜨겁다태그

보관