2011-01-15 15 views
26

Tôi vừa nhầm lẫn về cách triển khai một cái gì đó theo cách tổng quát trong C++. Đó là một chút phức tạp, vì vậy hãy để tôi giải thích từng bước.Chức năng mẫu làm đối số mẫu


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

void a(int) { 
    // do something 
} 
void b(int) { 
    // something else 
} 


void function1() { 
    a(123); 
    a(456); 
} 
void function2() { 
    b(123); 
    b(456); 
} 

void test() { 
    function1(); 
    function2(); 
} 

Đó là một cách dễ dàng đáng chú ý rằng function1function2 làm như vậy, với phần duy nhất khác nhau là chức năng nội bộ.

Vì vậy, tôi muốn thực hiện function chung để tránh tình trạng thừa mã. Tôi có thể làm điều đó bằng cách sử dụng con trỏ hàm hoặc mẫu. Hãy để tôi chọn thứ hai cho bây giờ. Suy nghĩ của tôi là nó tốt hơn vì trình biên dịch chắc chắn sẽ có thể nội tuyến các chức năng - tôi có đúng không? Trình biên dịch có thể vẫn inline các cuộc gọi nếu chúng được thực hiện thông qua con trỏ hàm? Đây là câu hỏi phụ.

OK, trở lại điểm ban đầu ... Một giải pháp với các mẫu:

void a(int) { 
    // do something 
} 
void b(int) { 
    // something else 
} 

template<void (*param)(int) > 
void function() { 
    param(123); 
    param(456); 
} 

void test() { 
    function<a>(); 
    function<b>(); 
} 

Tất cả OK. Nhưng tôi đang gặp phải vấn đề: Tôi vẫn có thể làm điều đó nếu ab là chính họ?

template<typename T> 
void a(T t) { 
    // do something 
} 

template<typename T> 
void b(T t) { 
    // something else 
} 

template<...param...> // ??? 
void function() { 
    param<SomeType>(someobj); 
    param<AnotherType>(someotherobj); 
} 

void test() { 
    function<a>(); 
    function<b>(); 
} 

Tôi biết rằng một số mẫu có thể là một trong:

  • một loại,
  • một kiểu mẫu,
  • một giá trị của một loại.

Không ai trong số đó dường như bao gồm trường hợp của tôi. Câu hỏi chính của tôi là: Làm cách nào để giải quyết điều đó, tức là định nghĩa function() trong ví dụ cuối cùng?

(Có, con trỏ hàm dường như là giải pháp trong trường hợp chính xác này - miễn là chúng cũng có thể được gạch chân - nhưng tôi đang tìm giải pháp chung cho loại sự cố này).

Trả lời

25

Để giải quyết vấn đề này với mẫu, bạn phải sử dụng thông số mẫu mẫu. Thật không may, bạn không thể vượt qua chức năng mẫu mẫu dưới dạng một loại, vì nó phải được khởi tạo trước tiên. Nhưng có một cách giải quyết với cấu trúc giả. Dưới đây là một ví dụ:

template <typename T> 
struct a { 

    static void foo (T = T()) 
    { 
    } 

}; 

template <typename T> 
struct b { 

    static void foo (T = T()) 
    { 
    } 

}; 

struct SomeObj {}; 
struct SomeOtherObj {}; 

template <template <typename P> class T> 
void function() 
{ 
    T<SomeObj>::foo(); 
    T<SomeOtherObj>::foo(); 
} 

int main() 
{ 
    function<a>(); 
    function<b>(); 
} 
+0

Không chắc chắn lý do tại sao điều này đã được giảm giá. Nó không hoàn toàn thỏa đáng nhưng nó giải quyết vấn đề. –

+0

Vì vậy, để tổng kết: giải pháp duy nhất mà sẽ làm cho nó có thể nội tuyến các cuộc gọi là để thay thế các chức năng với functors? Hơi khó sử dụng, nhưng hoàn toàn có thể chấp nhận được. Cảm ơn! – Kos

+1

Nhưng tôi thừa nhận rằng tôi rất ngạc nhiên sau khi bạn nói rằng không thể thực hiện cuộc gọi bằng địa chỉ ... Nếu địa chỉ có thể được xác định trong thời gian biên dịch bằng với địa chỉ của hàm đã cho, tôi mong đợi trình biên dịch đủ thông minh. :) Strange ... – Kos

0

Đây là một cách. Nó có thể không phải là tốt nhất, nhưng nó hoạt động:

template <typename T, T param> 
void function() { 
    param(123); 
    param(456); 
} 

void test() 
{ 
    function< void(*)(int), a<int> >(); // space at end necessary to compiler 
    function< void(*)(int), b<int> >(); // because the C++ grammar is ambiguous 
} 

Có hay không chúng sẽ được inlined phụ thuộc vào trình biên dịch, nhưng tôi sẽ ngạc nhiên nếu chúng không.

CHỈNH SỬA: Được rồi, hôm nay tôi hơi vắng mặt và bỏ qua phần thông số của các loại khác nhau. Lỗi của tôi.

Có thể có một cách khéo léo để làm điều này với các mẫu, nhưng đây là cách dễ nhất tôi có thể nghĩ ra:

#define function(x) do { x<thing1>(obj1); x<thing2>(obj2) } while(0) 

Tôi biết, tôi biết, "macro là ác," blah blah blah. Nó hoạt động. Nếu function cần phức tạp hơn ví dụ của bạn, bạn có thể gặp vấn đề, nhưng nó dễ dàng hơn nhiều so với bất cứ thứ gì tôi có thể đưa ra.

+0

Nhưng xin lưu ý rằng 'function' sẽ muốn gọi instantiations khác nhau của tham số mẫu chức năng. – Kos

+0

@Kos - Có phải '# define' nằm ngoài câu hỏi không? –

+0

Vâng, nó _is_ một "phương sách cuối cùng" sẽ hoạt động :), nhưng không thoải mái khi chỉnh sửa, gỡ lỗi, không thể ở trong không gian tên ... Tôi muốn tìm giải pháp dựa trên nền không dựa trên mẫu. – Kos

-2
template < typename F > 
void function(F f) 
{ 
    f(123); 
} 

void a(int x) { ... } 

struct b { void operator() (int x) { ... } }; 

void outer() 
{ 
    function(&a); 
    function(b()); 
} 
+0

Đây không phải là những gì OP muốn. –

+1

Cảm ơn, nhưng điều này không liên quan đến vấn đề tôi đã mô tả. Trong trường hợp này, một lệnh 'function' đã cho chỉ sử dụng 1 instantiation của một tham số function/functor. Vui lòng đọc lại câu hỏi. – Kos