2017-02-13 12 views
6

tôi muốn làm một điều đơn giản:Làm thế nào để sử dụng lambda làm đối số mẫu với giá trị mặc định trong C++?

void DoUntil(auto predicate = [] { return false; }); 

Rõ ràng điều này không làm việc - tôi phải sử dụng một mẫu đối số:

template <typename P> 
void DoUntil(P predicate = [] { return false; }); 

Nhưng tuyên bố này không làm việc, hoặc - các Clang đưa ra một lỗi:

error: no matching function for call to …
note: candidate template ignored: couldn't infer template argument 'P'

Nếu tôi làm gọi hàm không có đối số, bằng cách nào đó trình biên dịch không suy ra loại từ một đối số mặc định:

int main() { DoUntil(); } 

Tôi không muốn sử dụng std::function<> bằng bất kỳ cách nào.

Có giải pháp nào khác có thể cho vấn đề của tôi không?

+1

Đó là ngữ cảnh không được suy luận. Được trích từ [cppreference] (http: //en.cppreference.com/w/cpp/language/template_argument_deduction) ngữ cảnh không suy luận, Một tham số mẫu được sử dụng trong kiểu tham số của tham số hàm có đối số mặc định đang được sử dụng trong cuộc gọi mà việc khấu trừ đối số đang được thực hiện. – felix

+0

Tại sao bạn không muốn sử dụng 'std :: function'? –

Trả lời

6

Sử dụng quá tải hàm thay vì tính năng đối số mặc định. Tạo một phi mẫu hàm không có đối số ngoài các mẫu chức năng:

void DoUntil() ; 

template <typename P> 
void DoUntil(P predicate) ; 

Phiên bản không có đối đơn giản có thể gọi phiên bản mẫu với lambda bạn muốn sử dụng như vị mặc định:

void DoUntil() { DoUntil([] { return false; }); } 

vấn đề với cách tiếp cận ban đầu của bạn là bạn đang cố gắng để cung cấp một mặc định mẫu chuyên môn bằng cách xác định một valu đối số mặc định e, nhưng không chỉ định mẫu mặc định. Mặc dù không có sự tham gia của lambdas, sau đây sẽ không làm việc vì T không có một loại mặc định, mặc dù t có một giá trị mặc định:

template <typename T> 
void Foo(T t = 3); 

Điều cần thiết là phải xác định một loại mặc định cho T sử dụng <typename T = int>.

Như đã nêu trong câu trả lời của WhiZTiM, loại mặc định cho trường hợp liên quan đến hàm lambda phải được khấu trừ bằng cách sử dụng decltype. Điều này tất nhiên là vì lambdas có các kiểu duy nhất chỉ được biết đến với trình biên dịch.

3

Một lambda là một kiểu ẩn danh không có hàm tạo mặc định (do nguyên nhân, bạn có thể sử dụng hàm tạo bản sao/di chuyển của nó nếu có). Nếu bạn phải đi theo con đường lambda, bạn có thể làm:

namespace detail{ auto predicate = [] { return false; }; } 

template <typename P = decltype(detail::predicate)> 
void DoUntil(P pred = detail::predicate); 

Thay vì cố gắng để fiddle xung quanh với lambdas. Bạn có thể đi theo con đường cũ tốt:

namespace detail{ 
    struct DefaultPredicate{ bool operator()() const { return false; } }; 
} 

template <typename P = detail::DefaultPredicate> 
void DoUntil(P predicate = P{}); 

Hoặc tốt hơn vẫn là Kyle Strand answered.

+0

Nếu bạn định đặt một lambda ở phạm vi không gian tên, hãy đặt nó thành 'const' để nó trở nên tĩnh hoàn toàn. – ildjarn

+0

Ah, tôi đã tự hỏi nếu cung cấp một đối số mặc định sẽ làm việc nếu các mẫu-đối số đã được mặc định đúng. Xuất sắc. –

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