7

C++ では、非型のテンプレート パラメーターをポインター (関数ポインター、型など) にすることができます。最近、これが何に役立つかについて質問しました。これは、回答の 1 つに対するフォローアップです。

問題の関数ポインタである関数引数から、関数ポインタ テンプレート パラメータのを推測することは可能ですか? 例えば:

using VoidFunction = void(*)();

template <VoidFunction F>
void templ(VoidFunction);

...

void func();  // a VoidFunction

...

templ<func>(func);  // works, but I have to specify the template parameter explicitly
templ(func);        //  <-- I would like to be able to do this

この控除を実現する方法はありますか?関数引数がコンパイル時にコード内の関数に解決できる限り、コンパイラの実装者の観点からは技術的に可能と思われます。

この背後にある動機について疑問がある場合は、この回答の下のコメント、特に実装の最適化の可能性を参照してくださいstd::bind()

編集: のように、関数の引数を削除してテンプレートの引数を使用するだけでよいことがわかりましたtempl<func>()。関数引数を追加した唯一の目的は、テンプレート引数を渡す必要がないようにすることでした。

私が本当に欲しいのは、次のように関数ポインターの型も推測することだと思います。

template <typename Function, Function F>
void templ(/* something */);

そして、呼び出すことができます

templ(func);

また

templ<func>();

関数ポインターの単一の言及から型と値の両方を推定します。

それが今より理にかなっていることを願っています。

4

1 に答える 1

3

関数のテンプレート引数は、関数のテンプレート パラメーターの型から推定されます。テンプレート引数は、その型が許可された形式の 1 つである場合にのみ、その型から推測できます。許可されるフォームは [temp.deduct.type] で指定されます。

テンプレート引数はいくつかの異なるコンテキストで推測できますが、いずれの場合も、テンプレート パラメーターに関して指定された型 (それを呼び出すP) が実際の型 (それを呼び出す) と比較され、Aテンプレート引数の値を見つける試みが行われます (型パラメーターの型、型以外のパラメーターの値、またはテンプレート パラメーターのテンプレート) をP、推定値の置換後 (推定値と呼びますA)、 と互換性がありAます。

テンプレート型引数T、テンプレート テンプレート引数TT、またはテンプレート非型引数は、次の形式のいずれかである場合にi推定できます。PA

T
cv-list T
T*
T&
T[整数定数]
template-name (ここで、template-name はクラス テンプレートを参照します)
タイプ(*)(T)
T(*)()
T(*)(T)
Tタイプ::*
タイプ T::*
TT::*
T (タイプ::*)()
タイプ (T::*)()
タイプ (タイプ::*)(T)
タイプ (T::*)(T)
T (タイプ::*)(T)
T (T::*)()
T (T::*)(T)
タイプ[i]
template-name<i> (ここで、template-name はクラス テンプレートを参照します)
TT<T>
TT<i>
TT<>

where(T)は、少なくとも 1 つの引数タイプに が含まれる引数リストT()表し、どのパラメータにも が含まれない引数リストを表しますT。同様に、<T>は、少なくとも 1 つの引数に が含まれるテンプレート引数リストT<i>表し、少なくとも 1 つの引数に が含まれるテンプレート引数リストを表し、iおよびは、引数にや<>が含まれないテンプレート引数リストを表します。Ti

非型テンプレート引数のみを考慮する場合、関連するフォームは次を含むフォームですi

タイプ[i]
template-name<i> (ここで、template-name はクラス テンプレートを参照します)
TT<i>

したがって、関数ポインタである関数引数の値から直接値を推測することはできません。ただし、関数パラメーターが指定された形式の 1 つを持っている場合、非型テンプレート引数の値を推測することは可能です。

次のコードは、非型テンプレート引数値を というクラス テンプレートにラップすることで、これを実現していますNonType。のパラメータはfの形式template-name<i>であり、型ではないテンプレート引数の値を推測できるようにします。

template<typename T, T value>
struct NonType {};

template<typename T, T value>
void f(NonType<T, value>)
{
}

void g();

struct A
{
    void f();
    int m;
};

int i;

#define MAKE_NONTYPE(value) NonType<decltype(value), (value)>()

int main()
{
    f(MAKE_NONTYPE(0)); // NonType<int, 0>
    f(MAKE_NONTYPE(&g)); // NonType<void(*)(), &g>
    f(MAKE_NONTYPE(&A::f)); // NonType<void(A::*)(), &A::f>
    f(MAKE_NONTYPE(&A::m)); // NonType<int A::*, &A::m>
    f(MAKE_NONTYPE(&i)); // NonType<int*, &i>
}

decltypeおよびMAKE_NON_TYPEマクロは、完全なテンプレート引数リストを書き出す必要がないように、便宜上のみここで使用されていることに注意してください。NonType

于 2013-07-23T10:16:24.260 に答える