Mã này thất bại trong việc biên dịch ở hầu hết các trình biên dịch nhưng lúc đầu tôi bằng trực giác mong đợi SFINAE để bảo vệ tôi:SFINAE, khấu trừ vs instantiation
typedef void (*A)();
template < typename T >
struct a_metafun { typedef typename T::type type; };
template < typename T >
typename a_metafun<T>::type f(T) {}
template < typename T>
void f(T(*)()) {}
int main() { f(A()); }
tôi có thể sửa chữa các vấn đề trong ít nhất hai cách:
1) Thay đổi định nghĩa về "metafun" f() tới:
template < typename T > typename T::type f(T) {}
2) định nghĩa "a_metafun" như vậy mà nó phân tích T và có một loại nếu T có một và không làm tôi f nó không ... nhưng instantiates mà không có lỗi một trong hai cách:
BOOST_MPL_HAS_XXX_TRAIT_DEF(type)
typedef < template T, bool = has_type<T>::value >
struct a_metafun { };
typedef < template T >
struct a_metafun<T, true> { typedef typename T::type type };
Khi nhìn vào 14.8.2 (C++ 03) có vẻ như tôi chỉ định chính xác trong điều kiện nào mà SFINAE có thể áp dụng. Có một nơi nào tốt hơn để xem không? Thất bại trong quá trình khởi tạo của một mẫu đã được rút ra, ngay cả khi khấu trừ một mẫu khác, dường như không được đưa vào danh sách này.
Một hướng khác mà tôi đã thực hiện để giải thích điều gì làm cho điều này bất hợp pháp là việc khấu trừ a_metafun đã diễn ra và sự khởi tạo của nội bộ của nó là nguyên nhân gây ra lỗi. SFINAE không áp dụng trong quá trình khởi tạo nhưng chỉ trong khi khấu trừ, hoặc tôi có sai ở đó không? Tuy nhiên, trong trường hợp thứ hai, a_metafun đang được chính xác, và được khởi tạo tốt nhưng nó đơn giản không có định nghĩa "type" bên trong, có nghĩa là mẫu cố gắng khởi tạo nó không thành công do thay thế.
Về cơ bản, tôi tự hỏi điều gì trong tiêu chuẩn xác định hành vi mà tôi đang chứng kiến. Mỗi trình biên dịch tôi đã thử phàn nàn, thậm chí là comeau. Tôi có ý kiến rằng họ đúng khi làm như vậy, tôi không hoàn toàn chắc chắn là tại sao.
Vì vậy, các chuyên gia ... là gì? Tại sao việc khởi tạo loại, ngay cả trong bối cảnh khấu trừ trong f() gây ra lỗi hơn là loại trừ SFINAE?
Tôi nghĩ rằng nên thất bại trong C++ 11, chứ không phải trong C++ 03 mặc dù. Quy tắc SFINAE (hay đúng hơn là * từ *) được thay đổi một chút trong C++ 11. – Nawaz