4

次のコードがあるとします。

#include <iostream>
#include <functional>

template <int func(int)>
struct S : std::unary_function<int, int>
{
    int operator()(int x) const
    {
        return func(x);
    }
};

int foo(int x)
{
    return x;
}

int main()
{
    S<foo> s;

    std::cout << s(42) << std::endl;
}

これは、関数をファンクター内にラップする方法として問題なく機能します。つまり、他のテンプレート化された関数で使用できることを意味します (sortたとえば、(ファンクターが正しいシグネチャを持っていると仮定して))。可能なすべての戻り値/引数の型に対してファンクター構造体を作成したくない (現実的にはできません) ため、次のことを試しました。

template <template <typename R, // Make the return type and argument type template parameters!
                    typename A> R func(A)>
struct S : std::unary_function<R, A>
{
    R operator()(A arg) const
    {
        return func(arg);
    }
};

それはうまくいきませんでした。コンパイルエラーが発生しました。それで、私は試しました:

template <typename R, typename A, R func(A)>
struct S : std::unary_function<R, A>
{
    R operator()(A arg) const
    {
        return func(arg);
    }
};

これはうまくいきました。残念ながら、のインスタンス化をより良いものではなく変更するS必要がありました。S<int, int, foo> s;S<foo> s;

S<foo> s;で関数の戻り値の型と引数の型をハードコーディングしないように、テンプレート引数として渡された関数をテンプレート化することはまったく可能Sですか?

私の google-foo は特定の答えを見つけることができませんでした。

編集:今、これが不可能かどうか疑問に思っています。foo「オーバーロードされた関数はどうなるの?」と思っただけです。私の知る限り、戻り値/引数の型を明示的に述べるときにどちら fooを使用するかを知る方法はありません。これは正しい考えでしょうか? これは、私の最初の質問に対する答えが「いいえ、不可能です」ということですか?S<foo> s;

4

4 に答える 4

3

残念ながら、関数を渡すために必要な変換を防ぐ唯一の方法だと思います。ただし、以下のコードのように、(1)関数引数(2)関数が返すタイプを推測するのに役立つ関数テンプレートを追加できます。

template < typename R, typename A >
R result_of( R(A) );

template < typename R, typename A >
A arg0_of( R(A) );

次に、それらを使用して必要な関数オブジェクトを作成し、コンパイラーに可能な最適化を実行させることができます。

#define get_call( f ) call_t< decltype(result_of(f)), \
                              decltype(arg0_of(f)), f >()

// same as the class 'S'
template < typename R, typename A,
           R unary( A ) >
struct call_t : std::unary_function<A,R> {
    R operator()( A arg ) const {
        return unary( arg );
    }
};

ユーティリティを使用します。

int neg( int arg ) {
    return -arg;
}

auto s = get_call( neg );
cout << s( 1 ) << endl;  // outputs: -1

関数テンプレートでも機能します。もちろん、引数をテンプレートに渡す必要があります。

template < typename T >
T square( T arg ) {
    return arg * arg;
}

template <>
int square( int arg ) {
   cout << "square<int>()" << endl;
   return arg * arg;
}

auto sq = get_call( square<int> );
cout << sq( 12 ) << endl; // outputs: square<int>()
                          //          144

編集:オーバーロードされた関数の場合、変換を実行して、呼び出したいバージョンをコンパイラーに通知できます。

int cube( int arg ) {
    return arg * arg * arg;
}

float cube( float arg ) {
    return arg * arg * arg;
}

typedef float (*chosen)( float );
auto cu = get_call( (chosen)cube );
cout << showpoint << cu( 4 ) << endl; // outputs: 64.0000
于 2013-01-22T13:07:14.913 に答える
2

それは不可能です。これは、原則として次の問題と同じ問題です。次のように定義されているA<100>場所に書き込みたい場合。A

template<T N>
struct A {};

与えられたN100、でTあることがわかりますint。罰金。これは人間の心では推測できますが、C ++ 11標準に100%準拠している場合でも、コンパイラーでは推測できません。私はここでまったく同じ問題を抱えています:

-

だから私が思う代替ソリューションはこれです:

template <typename R, typename A>
struct S : std::unary_function<R, A>
{
    typedef R (*Fun)(A);
    Fun func;
    S(Fun f) : func(f) {}
    R operator()(A arg) const
    {
        return func(arg);
    }
};

そして、MakeS関数を次のように定義します。

template<typename R, typename A>
S<R,A> MakeS(R (*fun)(A)) 
{  
    return S<R,A>(fun); 
}

あなたはそれを次のように使うことができます:

auto s = MakeS(foo);

または、単にこれ:

S<int,int> s(foo);

この代替案の欠点は、関数fooが現在インライン化される機会がないことです。

于 2013-01-22T05:49:21.207 に答える
2

タイプ以外のテンプレート テンプレート パラメータが必要なようです。ただし、テンプレート テンプレート パラメーターの唯一の有効な構文は ですtemplate < template-parameters > class。(「テンプレート テンプレート パラメータのテンプレート引数は、クラス テンプレートまたはエイリアス テンプレートの名前であり、id-expression として表されます。」§ 14.3.3)

コンストラクター引数が関数ポインターであるテンプレート化されたクラスを作成できますが、間接的な関数呼び出しが作成されるのではないかと心配していると思います。

于 2013-01-22T05:30:38.090 に答える
0

これはうまくいきますか?

それほど良くはないかもしれませんがS<foo>、インスタンス化の時点で引数を 1 のままにします。

int f(int) { return 0; }


template<class R, class A> struct S
{
    typedef R(*FTYPE)(A);
    typedef R RET;
    typedef A ARG;
};

template<class R, class A> S<R, A> FW(R(f)(A));

template<class T> struct F  : std::unary_function<typename T::RET, typename T::ARG>
{

};

int main()
{
    F<decltype(FW(f))> o;
}
于 2013-01-22T06:29:58.323 に答える