Truyền con trỏ hàm từ một mảng các con trỏ hàm làm đối số mẫu


9

Tôi muốn chuyển một con trỏ hàm từ một mảng các con trỏ hàm làm đối số mẫu. Mã của tôi dường như biên dịch bằng MSVC mặc dù Intellisense phàn nàn rằng có gì đó không đúng. Cả gcc và clang đều không biên dịch mã.

Hãy xem xét ví dụ sau:

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 biên dịch mã nhưng Intellisense đưa ra lỗi sau:invalid nontype template argument of type "const FunctionPointer"

gcc không thể biên dịch với thông báo sau:

<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 không biên dịch với thông báo sau:

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

Câu hỏi:

wrapper_function<functions[0]>();hợp lệ hay không?

Nếu không, có điều gì tôi có thể làm để chuyển functions[0]thành đối số mẫu wrapper_functionkhông? Mục tiêu của tôi là xây dựng một mảng mới các con trỏ hàm tại thời gian biên dịch, với nội dung { wrapper_function<functions[0]>, ..., wrapper_function<functions[std::size(functions) - 1]> }.


Hmm thật thú vị, tôi nghĩ vấn đề là bạn đang sử dụng một giá trị (một con trỏ) thay vì một loại. Nhưng thậm chí wrapper_function<decltype(functions[0])>()không biên dịch.
CoryKramer

6
Có vẻ như hoạt động trong C ++ 17 ... bây giờ để tìm sự khác biệt về tiêu chuẩn ...
AndyG

Câu trả lời:


5

Biểu hiện wrapper_function<functions[0]>();bị cấm vì những điều sau đây:

14.3.2 Đối số không loại mẫu [temp.arg.nontype]

Đối số mẫu cho tham số mẫu không phải kiểu, không phải mẫu sẽ là một trong:

[...]

- một biểu thức không đổi (5.19) chỉ định địa chỉ của một đối tượng có lưu trữ tĩnh> thời lượng và liên kết bên ngoài hoặc bên trong hoặc một chức năng với liên kết bên ngoài hoặc bên trong, bao gồm các mẫu hàm và id mẫu chức năng nhưng loại trừ các thành viên lớp không tĩnh, được biểu thị (bỏ qua dấu ngoặc đơn) dưới dạng biểu thức & id, ngoại trừ dấu & có thể được bỏ qua nếu tên tham chiếu đến hàm hoặc mảng và sẽ bị bỏ qua nếu tham số mẫu tương ứng là tham chiếu; [...]

Nghiêm cấm sử dụng các con trỏ làm đối số mẫu không phải loại khác với dạng &id, vì vậy, về cơ bản, sau đây sẽ hoạt động:

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
}

và đoạn trích sau sẽ không hoạt động khi được biên dịch với tùy chọn C ++ 14:

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

Khi được biên dịch với tùy chọn C ++ 17, cách tiếp cận của bạn và cách trên đều có tác dụng:

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

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

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

Xem trực tiếp


Không chỉ biểu mẫu &id, mà còn idđược phép cho các hàm, như bạn đang thể hiện trong ví dụ và giá trị con trỏ null được cho phép rõ ràng ở dạng biểu thức không đổi.
quả óc chó

C ++ 17 thay thế bằng " biểu thức hằng được chuyển đổi ", nghĩa là nó cho phép xâu chuỗi các biểu thức hằng vì vậy wrapper_function<func>()cũng sẽ hoạt động.
rustyx

Ok sẽ kiểm tra và cập nhật câu trả lời sau khi tôi viết toàn bộ. Tnx
NutCracker
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.