2015-06-03 17 views
6

Tại sao không thể khấu trừ F cho proxy()?Không thể suy luận đối số mẫu là hàm

Điều này có thể xảy ra vì tôi đang hạn chế nó - chỉ cho các chức năng trả về int.

#include <utility> 
#include <iostream> 
#include <type_traits> 
using namespace std; 

int foo(int bar) { 
    cout << "int" << endl; 
    return 2; 
} 

float foo(float bar) { 
    cout << "float" << endl; 
    return 1; 
} 

template <typename F, typename... Args> 
typename enable_if< 
    is_same< 
     typename result_of<F(Args...)>::type, 
     int 
     >::value, 
    typename result_of<F(Args...)>::type 
    >::type 
proxy(F func, Args&&... args) { 
    return func(forward<Args>(args)...); 
} 

int main() { 
    proxy(foo, 5); 
} 

Dưới đây là lỗi:

b.cpp:29:17: error: no matching function for call to 'proxy(<unresolved overloaded function type>, int)' 
b.cpp:24:1: note: template argument deduction/substitution failed: 
b.cpp:29:17: note: couldn't deduce template parameter 'F' 
+0

Như có hai quá tải của hàm ... Trình biên dịch không thể suy ra giá trị trên cơ sở của một tương lai (tiếp theo) tham số của một hàm ...'proxy (static_cast (foo), 5);' sẽ làm thủ thuật ở đây –

Trả lời

4

Vấn đề là thế này:

proxy(foo, 5); 

Trình biên dịch sẽ cố gắng để suy ra loại foo, nhưng có 2 quá tải. Tất nhiên, nó có thể suy ra Args... từ 5, nhưng loại foo vẫn không thể khấu trừ, vì trình biên dịch không biết quá tải để chọn khi thực hiện khấu trừ loại.

Lưu ý rằng trình biên dịch cần phải biết loại F trong chữ ký của các chức năng, ví dụ ở đây, vì vậy SFINAE làm kỳ diệu của nó:

is_same< 
    typename result_of<F(Args...)>::type, 
    int 
>::value, 

Có là hoàn toàn không có cách nào cho nó để suy ra một cách chính xác các loại của F từ cuộc gọi proxy(foo, 5), vì vậy SFINAE không thể khởi động. Lưu ý rằng C++ không thể quá tải dựa trên loại trả về. Vì vậy, bạn sẽ không thể phân biệt hai hàm có cùng tên dựa trên kiểu trả về một mình. Bạn sẽ cần bằng cách nào đó để buộc một kết hợp tham số mà sẽ SFINAE ra quá tải không ứng cử viên.

Bằng cách nào đó liên quan: Deducing the return type of a standalone function

Và một báo có liên quan từ tiêu chuẩn, nhấn mạnh mỏ (nhờ @TC cho trỏ nó ra):

14.8.2.1 Suy luận đối số mẫu từ một cuộc gọi chức năng [tạm thời .deduct.call]/(6,2)

(6) When P is a function type, pointer to function type, or pointer to member function type:

  • (6.1) If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.

  • (6.2) If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.

+0

nhưng tại sao nó không thử với mỗi cái và xem nó sẽ nhận được bao nhiêu trong bản mẫu/thay thế mẫu ? Có cách nào để giải quyết vấn đề này mà không có diễn viên rõ ràng không? – onqtam

+0

@onqtam Tôi đoán nó quá phức tạp, đối với trình biên dịch tham số đầu tiên 'F' không liên quan gì đến' Args ... 'thứ hai. Tôi sẽ cố nghĩ về cách giải quyết. – vsoftco

+0

Vấn đề này có thể tái sản xuất mà không có đối số - chỉ khi sử dụng kiểu trả về ... Tôi đoán tôi nên đặt một ví dụ đơn giản hơn – onqtam

2

trong ví dụ của bạn foo tên một tập hợp các hàm quá tải, và mẫu khấu trừ đối số là không thể chọn o ne quá tải trên khác vì họ là cả hai trận đấu có thứ hạng như nhau.

Kiểm tra ràng buộc SFINAE của bạn không khởi động cho đến sau khi F bị suy giảm, do đó, không có sự trợ giúp nào trong việc giảm số float foo(float) từ tập hợp quá tải.

Giả sử bạn đổi tên hàm trả về float thành foof, sau đó ví dụ của bạn sẽ biên dịch. Nhưng nếu bạn đã thử gọi số proxy với foof làm đối số hàm, thì mã sẽ không biên dịch được nữa, lần này là do ràng buộc enable_if.

Để có được ví dụ của bạn để biên dịch trong trạng thái hiện tại của nó bạn phải disambiguate mà foo bạn đang đi qua để proxy

proxy(static_cast<int(*)(int)>(foo), 5); 
+0

Tôi đoán tôi chưa hiểu đầy đủ về SFINAE vì tôi nghĩ nó sẽ giúp tôi ở đây ... – onqtam

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