2015-03-16 12 views
9

Ich schreibe benutzerdefinierte Lazy String-Klasse.Mitglied des abhängigen typedef nicht definiert

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

Dann möchte ich diese Methoden außerhalb der Klassendeklaration definieren.

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

Aber ich habe Fehler kompilieren:

cannot define member of dependent typedef char_proxy

So kann ich nicht herausfinden, was ist hier Problem. Warum kann der Compiler die Verknüpfung char_proxy anstelle von lazy_basic_string :: char_proxy nicht verwenden?

Antwort

4

Dies scheint vom Standard nicht besonders gut spezifiziert zu sein. Die nächstgelegene ich erscheinen zu bekommen, ist [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. [...]

Dies bedeutet, tut aber nicht genau Zustand, dass eine Out-of-line soll Klassenvorlage Mitglied Definition der Klassenvorlage verweisen, indem sein Name und nicht über eine Alias-Vorlage.

Es sollte ziemlich einfach zu sehen sein, warum dies notwendig ist; als Alias-Vorlage in einer beliebig komplexe Berechnung, um würde der Compiler eine Verwendung eines Klassenschablone Element gegen eine mögliche Definition zu entsprechen führen kann, dass die Berechnung auf jede mögliche Kombination von Alias-Template-Parameter ausführen müssen:

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? 

Interessanterweise Klirren (3.7) erlaubt die Verwendung eines Alias-Vorlage in einem Mitglieds Definition Klassenvorlage, aber nur dort, wo es ist eine gerade Identitätsberechnung:

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

Welche Compiler verwenden Sie? Mit GCC 4.8, habe ich keine Möglichkeit gefunden, es zu machen zu kompilieren, aber auf Visual Studio 2015 Vorschau, wenn Sie leicht Ihren Code ändern, es erfolgreich kompiliert:

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

oder, wenn Sie es vorziehen:

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

Wie Sie bemerkt haben, könnte ich den Alias ​​nur entweder als Rückgabetyp oder um auf den Namen des Operators zuzugreifen, aber nicht beide.

Ich denke, Sie haben eine Art dunkler Bereich im Standard gefunden, weil der folgende Code unterschiedliche Verhalten auf VS und GCC auch hat. Es kompiliert auf VS 2015, aber nicht in 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{}; 
} 

In diesem Fall auf VS ich in der Lage war, sowohl den Alias ​​zu verwenden, um die Funktionsnamen für den Zugriff auf und den Rückgabetyp angeben.

+0

Ich benutze g ++ 4.7. Scheint, dass die Definition von Klassenmitgliedern durch Vorlagenalias nicht unterstützt wird, daher ist es besser, diese Funktion zu vermeiden. – eucpp

Verwandte Themen