関数ポインターの配列から関数ポインターをテンプレート引数として渡す


9

関数ポインターの配列から関数ポインターをテンプレート引数として渡したいのですが。Intellisenseが何かがおかしいと文句を言うのに、私のコードはMSVCを使用してコンパイルしているようです。gccとclangはどちらもコードのコンパイルに失敗します。

次の例を考えてみます。

static void test() {}

using FunctionPointer = void(*)();

static constexpr FunctionPointer functions[] = { test };

template <FunctionPointer function>
static void wrapper_function()
{
    function();
}

int main()
{
    test();  // OK
    functions[0]();  // OK

    wrapper_function<test>();  // OK
    wrapper_function<functions[0]>();  // Error?
}

MSVCはコードをコンパイルしますが、Intellisenseは次のエラーを出します:invalid nontype template argument of type "const FunctionPointer"

gccは次のメッセージでコンパイルに失敗します。

<source>: In function 'int main()':
<source>:19:33: error: no matching function for call to 'wrapper_function<functions[0]>()'
   19 |  wrapper_function<functions[0]>();  // Error?
      |                                 ^
<source>:8:13: note: candidate: 'template<void (* function)()> void wrapper_function()'
    8 | static void wrapper_function()
      |             ^~~~~~~~~~~~~~~~
<source>:8:13: note:   template argument deduction/substitution failed:
<source>:19:30: error: '(FunctionPointer)functions[0]' is not a valid template argument for type 'void (*)()'
   19 |  wrapper_function<functions[0]>();  // Error?
      |                   ~~~~~~~~~~~^
<source>:19:30: note: it must be the address of a function with external linkage

clangは次のメッセージでコンパイルに失敗します。

<source>:19:2: error: no matching function for call to 'wrapper_function'
        wrapper_function<functions[0]>();  // Error?
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:8:13: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'function'
static void wrapper_function()
            ^
1 error generated.

質問:

wrapper_function<functions[0]>();有効かどうか?

そうでない場合functions[0]、テンプレート引数として渡すことができることはありwrapper_functionますか?私の目標は、コンパイル時に、コンテンツを使用して、関数ポインタの新しい配列を構築すること{ wrapper_function<functions[0]>, ..., wrapper_function<functions[std::size(functions) - 1]> }です。


興味深いことに、問題は型ではなく値(ポインタ)を使用していることだと思いました。しかし、wrapper_function<decltype(functions[0])>()コンパイルもできません。
CoryKramer

6
C ++ 17で動作しているようです...標準の違いを見つけるために...
AndyG

回答:


5

wrapper_function<functions[0]>();次の理由により、式は禁止されています:

14.3.2テンプレートの非タイプ引数[temp.arg.nontype]

タイプ、テンプレート以外のテンプレートパラメータのテンプレート引数は、次のいずれかになります。

[...]

—静的ストレージ>期間および外部または内部リンケージを持つオブジェクトのアドレス、または外部または内部リンケージを持つ関数のアドレスを指定する定数式(5.19)。 (括弧は無視)&id-expressionとして。ただし、名前が関数または配列を参照する場合は&を省略でき、対応するテンプレートパラメータが参照の場合は&を省略します。[...]

フォーム以外の非型テンプレート引数としてポインターを使用することは禁止されている&idため、基本的には次のように機能します。

static void test() {}

using FunctionPointer = void(*)();

static constexpr FunctionPointer functions[] = { test };

template <FunctionPointer function>
static void wrapper_function()
{
    function();
}

int main()
{
    test();  // OK
    functions[0]();  // OK

    wrapper_function<test>();  // OK
    wrapper_function<&test>();  // OK
}

次のスニペットは、C ++ 14オプションでコンパイルすると機能しません。

constexpr auto func = &test;
wrapper_function<func>();

C ++ 17オプションでコンパイルすると、あなたのアプローチと上記のアプローチの両方が機能します。

int main()
{
    test();  // OK
    functions[0]();  // OK

    wrapper_function<test>();  // OK
    wrapper_function<&test>();  // OK
    wrapper_function<func>();  // OK

    wrapper_function<functions[0]>();  // OK
}

ライブを見る


例だけで示しているよう&idに、フォームだけでなくid関数にも使用できます。定数式の形式ではnullポインター値を明示的に使用できます。
クルミ

C ++ 17は、これを「変換された定数式」に置き換えます。つまり、定数式を連鎖させることができるためwrapper_function<func>()、機能します。
rustyx

全体を書いたら、OKをチェックして更新します。Tnx
NutCracker
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.