2015-03-16 14 views
9

Tôi đang viết lớp chuỗi tùy chỉnh lười biếng.Không thể xác định thành viên của typedef phụ thuộc

template <typename charT, typename traits = std::char_traits<charT>> 
class lazy_basic_string 
{ 
    class char_proxy 
    { 
     char_proxy& operator=(charT ch); 
    }; 

    char_proxy operator[](size_type i); 
} 

Sau đó, tôi muốn xác định các phương thức này ngoài khai báo lớp học.

template <typename charT, typename traits> 
using char_proxy = typename lazy_basic_string<charT, traits>::char_proxy; 

template <typename charT, typename traits> 
char_proxy<charT, traits>& char_proxy<charT, traits>::operator=(charT ch) 
{ 
    ... 
} 

Nhưng tôi đã nhận biên dịch báo lỗi:

cannot define member of dependent typedef char_proxy

Vì vậy, tôi không thể tìm ra vấn đề là những gì ở đây. Tại sao trình biên dịch không thể sử dụng phím tắt char_proxy thay vì lazy_basic_string :: char_proxy?

Trả lời

4

Điều này dường như không được chỉ định rõ ràng theo Tiêu chuẩn. Gần nhất tôi có thể xuất hiện để nhận được là [temp.class]:

3 - When a member function, a member class, a member enumeration, a static data member or a member template of a class template is defined outside of the class template definition, the member definition is defined as a template definition in which the template-parameters are those of the class template. The names of the template parameters used in the definition of the member may be different from the template parameter names used in the class template definition. The template argument list following the class template name in the member definition shall name the parameters in the same order as the one used in the template parameter list of the member. [...]

Điều này có nghĩa, mặc dù không chính xác tình trạng, rằng một định nghĩa thành viên lớp mẫu out-of-line nên tham khảo các mẫu lớp bằng tên của nó chứ không phải qua mẫu bí danh.

Sẽ rất dễ dàng để xem lý do tại sao điều này là cần thiết; như một mẫu bí danh có thể dẫn đến một tính cách độc đoán phức tạp, để phù hợp với việc sử dụng của một lớp mẫu thành viên chống lại một định nghĩa tiềm năng trình biên dịch sẽ phải thực hiện tính toán rằng trên tất cả các kết hợp có thể có của alias mẫu thông số:

template<class T> struct S { void f(); }; 
template<class T> using s_t = std::conditional_t<sizeof(T) % 8 == 0, 
    S<T>, S<T*>>; 
template<class T> void s_t<T>::f() {} 

int main() { S<int> s; s.f(); } // defined? 

Điều thú vị là, kêu vang (3.7) cho phép sử dụng một mẫu bí danh trong một định nghĩa thành viên lớp mẫu, nhưng chỉ khi nó là một tính bản sắc thẳng:

template<class> struct T { void f(); }; 
template<class C> using id_t = C; 
template<class C> using t_t = T<id_t<C>>; 
template<class C> void t_t<C>::f() {} // OK?? 
1

trình biên dịch gì bạn đang sử dụng? Với GCC 4.8, tôi đã tìm thấy không có cách nào để làm cho nó biên dịch, nhưng trên Visual Studio 2015 Preview, nếu bạn hơi sửa đổi mã của bạn, nó biên dịch thành công:

template <typename charT, typename traits> 
char_proxy<charT, traits>& lazy_basic_string<charT, traits>::char_proxy::operator=(charT ch) 
{ 
    return {}; 
} 

hoặc, nếu bạn thích:

template <typename charT, typename traits> 
typename lazy_basic_string<charT, traits>::char_proxy& char_proxy<charT, traits>::operator=(charT ch) 
{ 
    return{}; 
} 

Như bạn sẽ nhận thấy, tôi có thể sử dụng bí danh chỉ dưới dạng kiểu trả về hoặc để truy cập tên nhà điều hành, nhưng không phải cả hai.

Tôi nghĩ bạn đã tìm thấy một số loại khu vực tối trong tiêu chuẩn, bởi vì đoạn mã sau có các hành vi khác nhau trên VS và GCC. Nó biên dịch trên VS 2015, nhưng không phải trong GCC:

template<typename T> 
class A { 
    class B { 
     B& test(); 
    }; 
}; 

template<typename T> 
using B_alias = typename A<T>::B; 

template<typename T> 
B_alias<T>& B_alias<T>::test() 
{ 
    return{}; 
} 

Trong trường hợp này, trên VS tôi đã có thể sử dụng bí danh cả hai để truy cập tên hàm và để xác định kiểu trả về.

+0

Tôi đang sử dụng g ++ 4.7. Có vẻ như định nghĩa của các thành viên lớp theo bí danh mẫu không được hỗ trợ nên sẽ tốt hơn nếu bạn tránh tính năng này. – eucpp

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