Melewati pointer fungsi dari array pointer fungsi sebagai argumen templat

9

Saya ingin melewatkan pointer fungsi dari array pointer fungsi sebagai argumen templat. Kode saya tampaknya dikompilasi menggunakan MSVC meskipun Intellisense mengeluh bahwa ada sesuatu yang salah. Baik gcc dan dentang gagal mengkompilasi kode.

Perhatikan contoh berikut:

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 mengkompilasi kode tetapi Intellisense memberikan kesalahan berikut:invalid nontype template argument of type "const FunctionPointer"

gcc gagal mengkompilasi dengan pesan berikut:

<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

dentang gagal dikompilasi dengan pesan berikut:

<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.

Pertanyaan:

Apakah wrapper_function<functions[0]>();valid atau tidak?

Jika tidak, adakah yang bisa saya lakukan untuk meneruskan functions[0]sebagai templat argumen wrapper_function? Tujuan saya adalah untuk membangun array fungsi pointer baru pada waktu kompilasi, dengan konten { wrapper_function<functions[0]>, ..., wrapper_function<functions[std::size(functions) - 1]> }.

Matti
sumber
Hmm itu menarik, saya pikir masalahnya adalah bahwa Anda menggunakan nilai (pointer) bukan tipe. Tetapi bahkan wrapper_function<decltype(functions[0])>()tidak dikompilasi.
CoryKramer
6
Tampaknya bekerja di C ++ 17 ... sekarang untuk menemukan perbedaan dalam bahasa standar ...
AndyG

Jawaban:

5

Ekspresi wrapper_function<functions[0]>();dilarang karena hal berikut:

14.3.2 Templat argumen non-tipe [temp.arg.nontype]

Argumen templat-parameter-templat-templat non-ketik harus berupa:

[...]

- ekspresi konstan (5.19) yang menunjuk alamat suatu objek dengan durasi penyimpanan statis> dan hubungan eksternal atau internal atau suatu fungsi dengan hubungan eksternal atau internal, termasuk templat fungsi dan id templat fungsi tetapi tidak termasuk anggota kelas yang tidak statis, dinyatakan (mengabaikan tanda kurung) sebagai & ekspresi-id, kecuali bahwa & dapat dihilangkan jika nama mengacu pada fungsi atau array dan harus dihilangkan jika parameter template yang sesuai adalah referensi; [...]

Dilarang menggunakan pointer sebagai argumen templat non-tipe selain dari bentuk &idjadi, pada dasarnya, berikut ini akan berfungsi:

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
}

dan cuplikan berikut tidak akan berfungsi saat dikompilasi dengan opsi C ++ 14:

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

Ketika dikompilasi dengan opsi C ++ 17, pendekatan Anda dan yang di atas akan bekerja:

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

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

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

Lihat langsung

Alat pemecah buah keras
sumber
Tidak hanya formulir &id, tetapi juga iddiizinkan untuk fungsi, karena Anda menunjukkan dalam contoh dan nilai pointer nol secara eksplisit diizinkan dalam bentuk ekspresi konstan.
kenari
C ++ 17 menggantikannya dengan " ekspresi konstan yang dikonversi ", yaitu memungkinkan untuk mengaitkan ekspresi konstan sehingga wrapper_function<func>()juga akan berfungsi.
rustyx
Ok akan memeriksa dan memperbarui jawabannya setelah saya menuliskannya secara keseluruhan. Tnx
NutCracker