2017-10-02 17 views
7

두 개 이상의 예제 함수가 주어지면 템플릿 매개 변수로 제공되는 함수의 인수를 추론 할 수있는 템플릿 코드를 작성할 수 있습니까?함수 포인터에서 인수 목록을 추론하는 방법?

이것은 동기 부여 예입니다 /*???*/ 모두 사용에서

void do_something(int value, double amount) { 
    std::cout << (value * amount) << std::endl; 
} 

void do_something_else(std::string const& first, double & second, int third) { 
    for(char c : first) 
     if(third/c == 0) 
      second += 13.7; 
} 

template<void(*Func)(/*???*/)> 
struct wrapper { 
    using Args = /*???*/; 
    void operator()(Args&& ... args) const { 
     Func(std::forward<Args>(args)...); 
    } 
}; 

int main() { 
    wrapper<do_something> obj; //Should be able to deduce Args to be [int, double] 
    obj(5, 17.4); //Would call do_something(5, 17.4); 
    wrapper<do_something_else> obj2; //Should be able to deduce Args to be [std::string const&, double&, int] 
    double value = 5; 
    obj2("Hello there!", value, 70); //Would call do_something_else("Hello there!", value, 70); 
} 

, 나는 이러한 종류의 코드를 활성화 것이라고 거기에 넣을 수있는 것을 해결하려고 노력하고있다.

처음 사용하기 전에 Args이 정의되어 있지 않아 다음과 같이 작동하지 않습니다 (많은 구문 오류가 있다고 가정해야 함). 그래도 여전히 찾고 있습니다. 스스로 종류의 명시 적 서면을 필요로하지 않는 버전 :

template<void(*Func)(Args ...), typename ... Args) 
struct wrapper { 
    void operator()(Args ...args) const { 
     Func(std::forward<Args>(args)...); 
    } 
}; 

wrapper<do_something, int, double> obj; 
+0

http://en.cppreference.com/w/ cpp/유틸리티/기능/기능)? – bolov

+0

@bolov 내가 특별히 찾고있는 것은 제공된 '함수'에서'Args '를 추론하는 방법입니다. 'std :: function'는 타입 인자 목록에 명시 적으로 명시된 타입을 가지고 함수 포인터를 찾습니다. – Xirema

+0

C++ 17을 수락 하시겠습니까? wink wink – bolov

답변

5

17 C++로 우리가 Wrapper<do_something> w{} 구문 1)을 가능하게 자동 템플릿이 아닌 형식 매개 변수를 가질 수 있습니다.

Args...을 추론 할 때는 specialization을 사용하면됩니다.


1)

Wrapper<do_something> w{}; 
w(10, 11.11); 
template <auto* F> 
struct Wrapper {}; 

template <class Ret, class... Args, auto (*F)(Args...) -> Ret> 
struct Wrapper<F> 
{ 
    auto operator()(Args... args) const 
    { 
     return F(args...); 
    } 
}; 

(17) C++ 없이는는 Wrapper<do_something> w{} 좋은 구문이 불가능하다.

당신이 할 수있는 최선은 다음과 같습니다

template <class F, F* func> 
struct Wrapper {}; 

template <class Ret, class... Args, auto (*F)(Args...) -> Ret> 
struct Wrapper<Ret (Args...), F> 
{ 
    auto operator()(Args... args) const 
    { 
     return F(args...); 
    } 
}; 
C++ (17)
Wrapper<declype(do_something), do_something> w{}; 
+0

예제 코드가 GCC에서 컴파일되지 않습니다. https://godbolt.org/g/3WEksw – Xirema

+1

@ Xirema C++ 17은 구현 초기 단계입니다. clang은 문제없이 컴파일 할 수 있습니다. https://godbolt.org/g/DyArxa – bolov

4

,이 작업을 수행 할 수 있습니다

template <auto FUNC, typename = decltype(FUNC)> 
struct wrapper; 

template <auto FUNC, typename RETURN, typename ...ARGS> 
struct wrapper<FUNC, RETURN (*)(ARGS...)> { 
    RETURN operator()(ARGS ...args) { 
     return FUNC(args...); 
    } 
}; 

을 내가 WF에서이 기술을 배웠어요 ' s answer

+0

Bolov가 자신의 솔루션을 수정했는데, 실제로 이제는 그 솔루션을 더 좋아합니다. – geza

2

C++ 17 버전의 개선 : less template pa rameters 적절한 noexcept 주석 :

template<auto VFnPtr> struct 
wrapper; 

template<typename TResult, typename... TArgs, TResult (* VFnPtr)(TArgs...)> struct 
wrapper<VFnPtr> 
{ 
    TResult 
    operator()(TArgs... args) const noexcept(noexcept((*VFnPtr)(::std::forward<TArgs>(args)...))) 
    { 
     return (*VFnPtr)(::std::forward<TArgs>(args)...); 
    } 
}; 
0

(11) C++로 당신은 템플릿 make_wrapper 도우미 함수를 고려할 수 있습니다. 그러나이 방법을 사용하면 함수 포인터가 템플릿 매개 변수가 아닙니다. 대신, 함수 포인터가 비 정적 데이터 멤버에 의해 "수행"있다가 다음 예에 f_ 전화 : 당신이 [표준 : 기능] (평균

#include <iostream> 

void do_something(int value, double amount) { 
    std::cout << (value * amount) << std::endl; 
} 

void do_something_else(std::string const& first, double & second, int third) { 
    for(char c : first) 
    if(third/c == 0) 
     second += 13.7; 
} 

template<class Ret, class... Args> 
using function_pointer = Ret(*)(Args...); 

template<class Ret, class... Args> 
struct wrapper { 
    using F = function_pointer<Ret, Args...>; 

    F f_; 

    explicit constexpr wrapper(F f) noexcept : f_{f} {} 

    template<class... PreciseArgs>// not sure if this is required 
    Ret operator()(PreciseArgs&&... precise_args) const { 
    return f_(std::forward<PreciseArgs>(precise_args)...); 
    } 
}; 

template<class Ret, class... Args> 
constexpr auto make_wrapper(
    function_pointer<Ret, Args...> f 
) -> wrapper<Ret, Args...> { 
    return wrapper<Ret, Args...>(f); 
} 

int main() { 
    constexpr auto obj = make_wrapper(do_something); 
    obj(5, 17.4); 
    constexpr auto obj2 = make_wrapper(do_something_else); 
    double value = 5; 
    obj2("Hello there!", value, 70); 

    return 0; 
}