2012-01-12 21 views
5

Có thể suy ra tham số mẫu không phải kiểu từ tham số hàm mẫu không?Giảm bớt thông số mẫu không kiểu

xem xét mẫu đơn giản này:

template <int N> constexpr int factorial() 
{ 
     return N * factorial<N - 1>(); 
} 

template <> constexpr int factorial<0>() 
{ 
     return 1; 
} 

template <> constexpr int factorial<1>() 
{ 
     return 1; 
} 

Tôi muốn để có thể thay đổi factorial vì vậy mà tôi cách khác có thể gọi nó như thế này:

factorial(5); 

và để cho các con số trình biên dịch ra giá trị của N tại thời gian biên dịch. Điều này có khả thi không? Có lẽ với một số bổ sung C++ 11 ưa thích?

+0

Tại sao bạn sẽ muốn làm điều đó? Hàm 'factorial' không chấp nhận bất kỳ tham số nào.Lợi ích của 'giai thừa (5)' trên đúng 'giai thừa <5>() 'là gì? –

+0

@CodyGray: Tôi nghĩ ý tưởng sẽ tạo ra một hàm 'factorial' chung có thể tính toán kết quả tại thời gian biên dịch nếu nó được biểu diễn theo thời gian biên dịch, nhưng cũng có thể tính toán nó trong thời gian chạy nếu đầu vào là một biến bình thường. –

+0

@Matteo: Theo tôi hiểu, không có gì được tính toán trong thời gian chạy vì biểu thức được khai báo là 'constexpr'. Và dù sao đi nữa, tôi không hiểu tại sao lại có vấn đề khi chuyển một "biến số bình thường" thay vì 5 bằng cách sử dụng cú pháp chuẩn. Câu hỏi đặt ra ở đây là "làm thế nào tôi có thể tránh gõ dấu ngoặc nhọn", và tôi không hiểu động cơ. –

Trả lời

4

Không thể thực hiện được, trừ khi bạn có máy thời gian.

Tham số cho hàm được xử lý khi chạy. Có, trong trường hợp của bạn là một hằng số theo nghĩa đen, nhưng đó là trường hợp đặc biệt.

Trong định nghĩa hàm, tham số loại được cố định tại thời gian biên dịch (và do đó, có thể được sử dụng để suy ra các thông số mẫu), nhưng thông số giá trị chỉ cố định khi chạy.

Tại sao bạn cần điều này? Là nó chỉ vì vậy bạn không cần phải gõ của <> 's?

+0

Khá nhiều, tôi có một cơ sở mã rất lớn với các cuộc gọi đến một số chức năng mà tôi viết lại dưới dạng mẫu. Thay thế các tên là tầm thường, nhưng chuyển tất cả 'f (2, 3, 'abc', true)' thành 'f <2, 3, true> (" abc ")' là một chút phức tạp hơn. – pezcode

+1

Làm thế nào về một macro để chuyển đổi 'f (2, 3," abc ", true)' thành 'f_impl <2, 3, true> (" abc ")'? –

1

Tôi không nghĩ bạn có thể làm điều đó; cách duy nhất bạn có thể làm điều đó sẽ có tham số chức năng constexpr sẽ được thông qua sau đó làm thông số template cho phiên bản mẫu factorial, nhưng không chấp nhận tham số chức năng constexpr.

0

Không, nó không phải là có thể, trừ khi bạn muốn tạo một câu lệnh switch khổng lồ:

int getFactorial(const int v) 
{ 
    switch (v) 
    { 
    case 1 : return factorial<1>(); 
    case 2 : return factorial<2>(); 
    //etc 
    default: 
     ; 
    } 
    return 0; 
} 
0

Không, bạn không thể làm điều đó. Đối số mẫu chỉ có thể được suy ra từ đối số loại của đối số hàm, không phải là giá trị , sẽ không được biết chung lúc biên dịch.

Tất nhiên, bạn có thể viết lại factorial làm chức năng không phải là mẫu constexpr; sau đó nó sẽ được đánh giá tại thời gian biên dịch nếu các đối số được biết đến sau đó.

8

mã hiện tại của bạn thường sẽ được viết như sau, tôi tin rằng:

constexpr factorial (int n) 
{ 
    return n > 0 ? n * factorial(n - 1) : 1; 
} 

Nếu bạn gọi nó với một hằng số biểu hiện, chẳng hạn như factorial(5), sau đó tất cả các trình biên dịch ma thuật sẽ đi vào chơi. Nhưng nếu bạn làm int a = 3; factorial(a), sau đó tôi nghĩ rằng nó sẽ rơi trở lại trên một chức năng thông thường - nghĩa là nó sẽ không xây dựng một bảng tra cứu các câu trả lời được tính toán trước.

Nói chung, bạn nên đánh dấu mọi hàm và hàm tạo là constexpr nếu có thể. Bạn không mất gì, trình biên dịch sẽ coi nó như một hàm bình thường nếu cần thiết.

+1

Tôi không biết constexpr hoạt động từ chối như thế. Đáng buồn thay, mã chỉ là một ví dụ và tôi cần một mảng có kích thước cố định bên trong hàm thực tế, vì vậy tôi cần một mẫu có kích thước mảng làm tham số. – pezcode

+0

Có lẽ xây dựng một mảng các con trỏ hàm tới các hàm được lập biểu mẫu tại thời gian biên dịch và tìm chúng tại thời gian chạy? 'giai thừa [3] (.. khác args ..)' –

+0

@pezcode: thay đổi giai thừa cho một macro gọi mã mẫu, Aaron: youd được tốt hơn của việc xây dựng một mảng các kết quả –

0

Sử dụng macro ác:

#define factorial(X) factorial<X>() 
Các vấn đề liên quan