2013-07-19 9 views
6

C++ cho phép các tham số mẫu không phải là con trỏ, bao gồm cả con trỏ hàm, kiểu. Gần đây, tôi đã yêu cầu một số question về điều này hữu ích và đây là theo dõi one of the answers.Có cách nào để suy ra giá trị của tham số mẫu con trỏ hàm không?

Có thể suy ra giá trị của tham số mẫu con trỏ hàm, từ đối số hàm là con trỏ hàm được đề cập không? Ví dụ:

using VoidFunction = void(*)(); 

template <VoidFunction F> 
void templ(VoidFunction); 

... 

void func(); // a VoidFunction 

... 

templ<func>(func); // works, but I have to specify the template parameter explicitly 
templ(func);  // <-- I would like to be able to do this 

Có cách nào để nhận khoản khấu trừ này xảy ra không? Có vẻ như về mặt kỹ thuật có thể từ quan điểm của người triển khai trình biên dịch, miễn là đối số hàm có thể được giải quyết thành một hàm trong mã tại thời gian biên dịch.

Nếu bạn đang băn khoăn về động lực đằng sau điều này, hãy xem các nhận xét dưới this answer, đặc biệt là tối ưu hóa có thể có để thực hiện std::bind().

EDIT: Tôi nhận thấy rằng tôi có thể chỉ cần xóa đối số hàm và sử dụng đối số mẫu, như trong templ<func>(). Mục đích duy nhất của tôi về việc thêm vào đối số hàm là cố gắng tránh phải vượt qua đối số mẫu.

Tôi đoán những gì tôi thực sự muốn, cũng là để suy ra loại của con trỏ hàm, như trong:

template <typename Function, Function F> 
void templ(/* something */); 

và sau đó có thể gọi

templ(func); 

hoặc

templ<func>(); 

và có cả loại và giá trị được suy ra từ một bài hát e đề cập đến con trỏ hàm.

Hy vọng bây giờ có ý nghĩa hơn.

+0

Làm thế nào nó có thể suy ra nó? Ví dụ, tôi có thể làm điều này: 'template void foo (std :: size_t i) {int arr [N];/* fill */return arr [i];} '. Tôi chắc chắn sẽ muốn một lỗi nếu tôi đã xảy ra để quên các đối số mẫu khi khấu trừ này có thể được thực hiện. – chris

+0

Nghĩ về nó, tôi không chắc tôi hiểu tại sao nó cần phải được thông qua như một đối số chức năng. Không phải là 'templ (); 'đủ? – chris

+0

@chris: Phải, câu hỏi của tôi không có ý nghĩa nhiều như được viết :) Vui lòng xem chỉnh sửa của tôi. – HighCommander4

Trả lời

2

Đối số mẫu cho hàm được suy ra từ các loại tham số mẫu của hàm. Đối số mẫu chỉ có thể được suy ra từ một loại khi loại đó là một trong các biểu mẫu được phép. Các hình thức cho phép được quy định tại [temp.deduct.type]

đối số mẫu có thể được rút ra trong những bối cảnh khác nhau, nhưng trong từng trường hợp một loại được chỉ định trong điều kiện của mẫu tham số (gọi nó là P) được so sánh với loại thực tế (gọi là A) và cố gắng tìm các giá trị đối số mẫu (loại cho tham số kiểu, giá trị cho thông số không phải kiểu hoặc mẫu cho thông số mẫu) sẽ tạo P, sau khi thay thế các giá trị suy ra (gọi nó là suy ra A), tương thích với A.

Mẫu kiểu lập luận T, một mẫu template luận TT hoặc một mẫu phi kiểu lập luận i có thể suy ra nếu PA có một trong các hình thức sau:

T 
cv-list T 
T* 
T& 
T[integer-constant] 
template-name (where template-name refers to a class template) 
type(*)(T) 
T(*)() 
T(*)(T) 
T type::* 
type T::* 
T T::* 
T (type::*)() 
type (T::*)() 
type (type::*)(T) 
type (T::*)(T) 
T (type::*)(T) 
T (T::*)() 
T (T::*)(T) 
type[i] 
template-name&lti> (where template-name refers to a class template) 
TT<T> 
TT<i> 
TT<>

nơi (T) đại diện cho các danh sách đối số trong đó ít nhất một loại đối số chứa T() đại diện cho các danh sách đối số trong đó không có thông số nào chứa T. Tương tự, <T> đại diện cho danh sách đối số mẫu trong đó ít nhất một đối số chứa một danh sách đối số mẫu trong đó ít nhất một đối số chứa i<> đại diện cho danh sách đối số mẫu không có đối số nào chứa T hoặc i.

Khi xem xét chỉ không loại lập luận mẫu, các hình thức phù hợp là những người chứa i:

type[i] 
template-name&lti> (where template-name refers to a class template) 
TT<i>

Vì vậy nó không thể suy ra giá trị trực tiếp từ giá trị của một đối số chức năng đó là con trỏ hàm. Tuy nhiên, có thể suy ra giá trị của đối số mẫu không phải kiểu nếu thông số hàm có một trong các biểu mẫu được chỉ định.

Mã sau đây sẽ thực hiện việc này bằng cách gói giá trị đối số mẫu không phải kiểu trong mẫu lớp được gọi là NonType. Tham số của f là ở dạng template-name<i>, làm cho nó có thể cho giá trị của đối số mẫu không kiểu của nó được suy luận.

template<typename T, T value> 
struct NonType {}; 

template<typename T, T value> 
void f(NonType<T, value>) 
{ 
} 

void g(); 

struct A 
{ 
    void f(); 
    int m; 
}; 

int i; 

#define MAKE_NONTYPE(value) NonType<decltype(value), (value)>() 

int main() 
{ 
    f(MAKE_NONTYPE(0)); // NonType<int, 0> 
    f(MAKE_NONTYPE(&g)); // NonType<void(*)(), &g> 
    f(MAKE_NONTYPE(&A::f)); // NonType<void(A::*)(), &A::f> 
    f(MAKE_NONTYPE(&A::m)); // NonType<int A::*, &A::m> 
    f(MAKE_NONTYPE(&i)); // NonType<int*, &i> 
} 

Lưu ý rằng decltypeMAKE_NON_TYPE vĩ mô được sử dụng ở đây chỉ như là một tiện nghi, để tránh phải viết ra các mẫu đầy đủ danh sách đối số của NonType