2017-10-02 21 views
7

2つ以上の関数例が与えられている場合、テンプレートパラメータとして提供される関数の引数を推測できるテンプレートコードを記述することは可能ですか?関数ポインタから引数リストを引き出す方法は?

これが動機の例です:/*???*/の両方の用途で

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/utility/functional/function)? – bolov

+0

@bolov私が特に探しているのは、提供された 'Function'から' Args'を推論する方法です。 'std :: function'は、型パラメータリストに明示的に指定された型を持つことによって、関数ポインタを照合します。 – Xirema

+0

あなたはC++ 17を受け入れますか? wink wink – bolov

答えて

5

17 C++で、我々はWrapper<do_something> w{}構文1)を可能にする自動テンプレート非型パラメータを持つことができます。

Args...については、specializationでこれを行うことができます。

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...); 
    } 
}; 
Wrapper<do_something> w{}; 
w(10, 11.11); 

1) C++ 17がなければ、それは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_と呼ばれる:あなたが[STD ::関数](平均

#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; 
} 
関連する問題