7

Tôi đang viết một thư viện với nhiều đối tượng hàm có các lớp có một số quá tải operator() không phụ thuộc vào trạng thái của các lớp và không thay đổi nó. Bây giờ, tôi đã cố gắng làm cho mã của tôi hoạt động với nhiều API kiểu cũ (nó không phải là một nhu cầu ngẫu nhiên, tôi thực sự phải đối phó với các API đó) và do đó quyết định làm cho các đối tượng hàm chuyển đổi thành bất kỳ con trỏ hàm nào tương ứng với một trong các quá tải. Tại một số điểm, tôi nhận ra rằng tôi đã có quá nhiều chuyển đổi như vậy để hoạt động con trỏ chức năng và rằng tôi về mặt lý thuyết sẽ có thể viết một nhà điều hành chuyển đổi duy nhất variadic. Dưới đây là một lớp học thực hiện một hành variadic ví dụ:Chuyển đổi con trỏ chức năng biến thể

struct foobar 
{ 
    template<typename... Args> 
    using fptr_t = void(*)(Args... args); 

    template<typename... Args> 
    operator fptr_t<Args...>() const 
    { 
     return [](Args... args) { 
      // Whatever 
     }; 
    } 
}; 

Như bạn thấy, tôi đã sử dụng chuyển đổi lambda thực hiện chức năng con trỏ để thực hiện các nhà điều hành chuyển đổi, mà không phải là một vấn đề vì mỗi đối tượng chức năng tôi có là quốc tịch. Mục tiêu là để có thể sử dụng lớp học như sau:

int main() 
{ 
    void(*foo)(int) = foobar(); 
    void(*bar)(float, double) = foobar(); 
} 

g ++ không có vấn đề biên dịch mã này với ngữ nghĩa dự kiến. Tuy nhiên, kêu vang ++ rejects it với một mẫu lỗi thất bại thay:

main.cpp:21:11: error: no viable conversion from 'foobar' to 'void (*)(int)' 
    void(*foo)(int) = foobar(); 
     ^   ~~~~~~~~ 
main.cpp:11:5: note: candidate function [with Args = int] 
    operator fptr_t<Args...>() const 
    ^
1 error generated. 

Lưu ý rằng kêu vang ++ không có vấn đề với những hoạt động chuyển đổi như miễn là không có mẫu variadic có liên quan. Nếu tôi sử dụng một tham số mẫu duy nhất, nó sẽ không có vấn đề biên dịch mã. Bây giờ, đoạn mã trên có được chấp nhận hay từ chối bởi trình biên dịch không?

+4

Tôi nghĩ rằng đây là [cùng lỗi như này] (https: // llvm.org/bugs/show_bug.cgi?id=24032). Có một câu hỏi SO liên kết quá. Richard Smith [nói lỗi của nó] (http://stackoverflow.com/questions/31225888/pre-typedefing-a-variadic-function-pointer-argument#comment50471304_31225888) vì vậy tôi tin anh ấy :). –

+0

Cách giải quyết: chuyển đổi với 'mẫu toán tử F *()', thêm kiểm tra sfinae rằng nó là một kiểu hàm, trích xuất args bằng cách sử dụng các đặc điểm, giải nén bằng cách sử dụng trợ giúp, sử dụng trợ giúp để chuyển đổi sang con trỏ? – Yakk

Trả lời

1

Một lambda chỉ có thể được chuyển đổi thành một con trỏ hàm nếu nó không nắm bắt được, do đó mã của bạn sẽ hoạt động. Đây là hợp lý trong các tiêu chuẩn 5.1.2/p6 biểu thức Lambda [expr.prim.lambda] (Nhấn mạnh Mine):

The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function with C++ language linkage (7.5) having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

Vì vậy, tôi sẽ nộp nó như là một lỗi Clang.

Là một công trình xung quanh cho Clang, bạn có thể chuyển nó sang một std::function như hình dưới đây:

struct foobar 
{ 
    template<typename... Args> 
    using fptr_t = void(*)(Args... args); 

    template<typename... Args> 
    operator std::function<void(Args...)>() const 
    { 
     return [](Args... args) { 
      //... 
     }; 
    } 
}; 

int main() 
{ 
    std::function<void(int)> f1 = foobar(); 
    std::function<void(double, float)> f2 = foobar(); 
    f1(1); 
    f2(2.0, 1.0f); 
} 

Live Demo

+0

Vâng, tôi biết tất cả điều đó. Tôi có nghĩa là, tôi không yêu cầu một giải pháp cho vấn đề của tôi (tôi đã làm việc xung quanh nó một lúc rồi). Tôi chỉ yêu cầu một câu trả lời cho luật sư ngôn ngữ để biết trình biên dịch nào tôi sẽ gửi báo cáo lỗi: p – Morwenn

+0

@Morwenn bạn sẽ gửi báo cáo lỗi cho CLANG: P. – 101010

Các vấn đề liên quan