2015-05-20 26 views
5

Các mã sau đây nên được, như tôi biết, "không suy luận bối cảnh" (hay không?)bối cảnh Không suy chức năng variadic mẫu

template <class... X, class Y> 
void f(X... args, Y y) 
{ 

} 

int main() 
{ 
    f(12); 
    f<int, int, int>(1, 2, 3, 4); 
} 

nhưng g ++ 4.9 biên dịch nó cho cả instantiations của f trong main. .. Ai có thể giải thích?

+0

Các cuộc gọi có được tối ưu hóa không? –

Trả lời

0

Quy tắc đó chỉ áp dụng cho các mẫu lớp, không phải các hàm, vì các mẫu có thể được suy ra cho các hàm. Nếu bạn cố gắng mà vào một lớp học mẫu, bạn sẽ thấy các lỗi:

template <class... X, class Y> 
class C { // This won't compile. 
}; 

Để biết thêm thông tin, vui lòng tham khảo trang 7 trong http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf:

If a template-parameter of a class template is a template parameter pack, it must be the last template-parameter. Note: This is not a requirementThese are not requirements for function templates because template arguments might be deduced (14.8.2)

0

Cuộc gọi đầu tiên f(12) bị ốm - hình thành. Một tham số-pack mà không xuất hiện ở phần cuối của một tham số khai báo là một bối cảnh phi suy luận mỗi [temp.deduct.type] /p5.7:

The non-deduced contexts are:

— [..]

A function parameter pack that does not occur at the end of the parameter-declaration-list

Tiếp tục trong [temp.deduct.call ]/p1:

For a function parameter pack that occurs at the end of the parameter-declaration-list, the type A of each remaining argument of the call is compared with the type P of the declarator-id of the function parameter pack. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. When a function parameter pack appears in a non-deduced context (14.8.2.5), the type of that parameter pack is never deduced.

[ Example:

template<class ... Types> void f(Types& ...); 
template<class T1, class ... Types> void g(T1, Types ...); 
template<class T1, class ... Types> void g1(Types ..., T1); 

void h(int x, float& y) { 
    const int z = x; 
    f(x, y, z); // Types is deduced to int, float, const int 
    g(x, y, z); // T1 is deduced to int; Types is deduced to float, int 
    g1(x, y, z); // error: Types is not deduced 
    g1<int, int, int>(x, y, z); // OK, no deduction occurs 
} 

— end example ]

Vì vậy, các thông số gói X... không thể được suy luận bởi đối số của hàm và khấu trừ mẫu đối số thất bại. GCC chấp nhận cuộc gọi đầu tiên thay vì từ chối mẫu để không khấu trừ 12 do đó, nó dường như là một lỗi.

Cuộc gọi thứ hai, f<int, int, int>(1, 2, 3, 4), tuy nhiên, được định dạng đúng theo [temp.deduct]/p6. Các đối số mẫu được chỉ định rõ ràng được thay thế ngay lập tức cho các tham số mẫu của mẫu hàm. Điều này có nghĩa là X = {int, int, int}. trích lập luận mẫu sau đó tiến hành với Y được rút ra từ những tranh cãi ngoài cùng bên phải như int:

At certain points in the template argument deduction process it is necessary to take a function type that makes use of template parameters and replace those template parameters with the corresponding template arguments. This is done at the beginning of template argument deduction when any explicitly specified template arguments are substituted into the function type, and again at the end of template argument deduction when any template arguments that were deduced or obtained from default arguments are substituted.

Lưu ý rằng cũng ([temp.deduct]/p2):

There must not be more arguments than there are parameters unless at least one parameter is a template parameter pack, and there shall be an argument for each non-pack parameter.

Clang không chấp nhận các chức năng cuối cùng gọi, nhưng GCC có. Tôi tin rằng đây là một lỗi Clang.


Lưu ý rằng có một mở CWG issue 1609 liên quan đến việc sử dụng đối số mặc định sau khi xảy ra gói tham số. Ngoài ra còn có LLVM Bug 21774 để tranh chấp hành vi của Clang trong bối cảnh đó.

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