无法定义依赖typedef的成员

eup*_*upp 9 c++

我正在编写自定义的lazy string类.

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);
}
Run Code Online (Sandbox Code Playgroud)

然后我想在类声明之外定义这些方法.

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)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

但我得到编译错误:

无法定义依赖typedef char_proxy的成员

所以我无法弄清楚这里有什么问题.为什么编译器不能使用快捷方式char_proxy而不是lazy_basic_string :: char_proxy?

eca*_*mur 6

标准似乎并没有特别明确地规定这一点。我能看到的最接近的是[temp.class]:

3 - 当成员函数、成员类、成员枚举、静态数据成员或类模板的成员模板在类模板定义之外定义时,成员定义被定义为模板定义,其中模板-参数是类模板的参数。成员定义中使用的模板参数名称可能与类模板定义中使用的模板参数名称不同。成员定义中类模板名称之后的模板参数列表应以与成员模板参数列表中使用的顺序相同的顺序命名参数。[...]

这意味着,虽然并没有完全说明,一个外部类模板成员定义应该通过它的名称而不是通过别名模板来引用类模板。

应该很容易理解为什么这是必要的;因为别名模板可能导致任意复杂的计算,为了将类模板成员的使用与潜在定义相匹配,编译器必须对别名模板参数的每个可能组合执行该计算:

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?
Run Code Online (Sandbox Code Playgroud)

有趣的是,clang (3.7) 允许在类模板成员定义中使用别名模板,但仅限于直接身份计算的情况:

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??
Run Code Online (Sandbox Code Playgroud)