2015-03-16 13 views
9

Piszę niestandardową klasę leniwych ciągów znaków.Nie można zdefiniować elementu zależnego typedef

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); 
} 

Następnie chcę zdefiniować te metody poza deklaracją klasy.

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) 
{ 
    ... 
} 

ale mam skompilować błędu:

cannot define member of dependent typedef char_proxy

więc nie mogę dowiedzieć się, co jest problemem. Dlaczego kompilator nie może używać skrótu char_proxy zamiast lazy_basic_string :: char_proxy?

Odpowiedz

4

Wydaje się, że nie jest to szczególnie dobrze określone przez Standard. Najbliższy mogę wydawać się to [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. [...]

Oznacza to, choć nie dokładnie stan, że definicja członkiem out-of-line klasa szablon powinien odnosić się do szablonu klasy przez jego nazwę, a nie szablon aliasu.

Powinno być dość łatwo zrozumieć, dlaczego jest to konieczne; jako szablon alias może spowodować dowolnie złożonych obliczeń, w celu dopasowania do wykorzystania członka klasy szablonu przed potencjalnym definicji kompilator musiałby wykonać to obliczenie na każdej możliwej kombinacji parametrów szablonu Alias:

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? 

ciekawe, dzyń (3.7) pozwala na korzystanie z szablonu alias w definicji członkiem klasy szablonu, ale tylko wtedy, gdy jest to prosta kalkulacja tożsamość:

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

Co kompilatora używasz? GCC 4.8, znalazłem żadnego sposobu, aby go skompilować, ale Visual Studio 2015 Preview, jeśli nieco zmodyfikować kod, kompiluje pomyślnie:

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

lub, jeśli wolisz:

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

Jak można zauważyć, mógłbym użyć aliasu tylko jako typ zwracany lub uzyskać dostęp do nazwy operatora, ale nie do obu.

Myślę, że znalazłeś jakiś ciemny obszar w standardzie, ponieważ poniższy kod ma różne zachowania również w VS i GCC. Kompiluje na VS 2015, ale nie w 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{}; 
} 

W tym przypadku, na VS I był w stanie wykorzystać alias zarówno dostęp do nazwy funkcji i określić typ zwracanej.

+0

Używam g ++ 4.7. Wygląda na to, że definicja członków klasy według aliasu szablonu nie jest obsługiwana, więc lepiej będzie uniknąć tej funkcji. – eucpp

Powiązane problemy