Передача покажчика функції з масиву функціональних покажчиків як аргумент шаблону


9

Я хотів би передати покажчик функції з масиву вказівників функції як аргумент шаблону. Мій код, здається, компілюється за допомогою MSVC, хоча Intellisense скаржиться, що щось не так. І 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-вираз, за ​​винятком того, що & може бути опущено, якщо ім'я посилається на функцію чи масив, і опустити, якщо відповідний шаблон-параметр є посиланням; [...]

Забороняється використовувати вказівники як аргументи нетипового шаблону, окрім форми, &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дозволена для функцій, як ви демонструєте в прикладі, і значення нульового вказівника явно дозволено в формі постійного вираження.
волоський горіх

C ++ 17 замінює це на " перетворений константний вираз ", тобто це дозволяє ланцюг константних виразів, так що wrapper_function<func>()також буде працювати.
іржа

Ок перевірить і оновить відповідь після того, як я її напишу в цілому. Tnx
NutCracker
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.