Với "không phụ thuộc" ở đây tôi có nghĩa là "không phụ thuộc vào bất kỳ đối số mẫu nào khác của mẫu chức năng cụ thể đó".Các đối số mẫu mặc định không phụ thuộc của các mẫu chức năng có cho phép SFINAE không?
Khi trả lời this question, tôi nghĩ tôi đã tìm được câu trả lời, nhưng theo @Johannes (trong phần nhận xét cho câu trả lời của tôi), tôi hiểu sai tiêu chuẩn ở đây. Lấy ví dụ đơn giản sau:
#include <type_traits>
template<class T>
struct X{
template<class U = typename T::type>
static void foo(int){}
static void foo(...){}
};
int main(){
X<std::enable_if<false>>::foo(0);
}
Có bất kỳ sự đảm bảo rằng các biên dịch trên? GCC và Clang không đồng ý ở đây, như có thể thấy trong phiên bản trực tiếp khi chuyển đổi giữa chúng. Điều thú vị là, mặc dù, sau đây được chấp nhận bởi GCC:
#include <type_traits>
template<class T>
struct X{
template<bool = T::f()>
static void foo(int){}
static void foo(...){}
};
struct Y{
static bool f(){ return true; }
};
int main(){
X<Y>::foo(0);
}
Đoạn thứ hai sẽ chỉ in foo(int)
nếu T
chứa một constexpr
chức năng tĩnh f
. Một lần nữa, thật thú vị, nếu bạn xóa hoàn toàn f
từ Y
(hoặc vượt qua, giả sử, int
thay thế), GCC khiếu nại về thành viên bị thiếu, cho biết rằng nó không cho phép SFINAE - mâu thuẫn với quan sát trước đó. Clang có tất cả các biến thể và áp dụng SFINAE, và tôi tự hỏi nếu đó là những gì được đảm bảo bởi tiêu chuẩn.
(FWIW, MSVC với tháng mười một CTP thường đồng ý với Clang, nhưng tai nạn trên đoạn thứ hai nếu chức năng có mặt, có khả năng bởi vì họ không có constexpr
. Tôi đã gửi một báo cáo lỗi here.)
Nếu "đối số mẫu mặc định" được bao gồm trong "đối số mặc định", thì chúng cũng được đưa vào giải thích điểm giải thích, cho biết đó là điểm khởi tạo của mẫu chức năng. Tuy nhiên, tôi chủ yếu tự hỏi vì Clang chỉ chấp nhận tất cả các đoạn "như mong đợi". – Xeo
@Xeo nhưng điều đó rất khó xảy ra, bởi vì nó chỉ nói về các cuộc gọi chức năng. Một đối số mẫu mặc định có thể được sử dụng không chỉ trong các cuộc gọi hàm, mà còn trong việc sử dụng các cá thể mẫu lớp của bất kỳ hương vị nào (trên thực tế, trường hợp duy nhất cho C++ 03) và chuyên môn hóa rõ ràng và diễn giải các mẫu hàm.Tất cả những gì không được đề cập ở bất kỳ đâu trong các quy tắc về sự khởi tạo ngầm cũng như các quy tắc về điểm khởi tạo. Tôi khuyên bạn nên mở một Clang PR. –
@Xeo Ngoài ra, một đối số mẫu mặc định của hàm có thể được sử dụng mà không có sự khởi tạo hàm. Một cái gì đó như 'decltype (& X :: template foo <>)' có thể trả về nó nhưng hàm sẽ không được sử dụng ODR. Yêu cầu SFINAE trong bối cảnh đó sẽ ngụ ý quá tải độ phân giải mà nếu không sẽ không xảy ra. – Potatoswatter