Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 无法定义从属typedef的成员_C++ - Fatal编程技术网

C++ 无法定义从属typedef的成员

C++ 无法定义从属typedef的成员,c++,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); } 模板 类

我正在编写自定义的惰性字符串类

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);
}
模板
类惰性\u基本\u字符串
{
类字符代理
{
字符代理和运算符=(图表ch);
};
char_代理运算符[](大小_类型i);
}
然后我想在类声明之外定义这些方法

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)
{
    ...
}
模板
使用char\u proxy=typename lazy\u basic\u string::char\u proxy;
模板
char\u proxy&char\u proxy::operator=(图表ch)
{
...
}
但我得到了编译错误:

无法定义从属typedef char_代理的成员

所以我不知道这里有什么问题。
为什么编译器不能使用快捷方式char\u proxy而不是lazy\u basic\u string::char\u proxy?

标准似乎没有特别明确地规定这一点。我能找到的最接近的是[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?
模板结构S{void f();};
使用s_t=std::conditional_t的模板;
模板无效s_t::f(){}
int main(){S;S.f();}//定义了吗?
有趣的是,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??
模板结构T{void f();};
使用id_t=C的模板;
使用t_t=t的模板;
模板无效t_t::f(){}//OK??

您使用的编译器是什么?对于GCC 4.8,我没有找到使其编译的方法,但在Visual Studio 2015预览版上,如果稍微修改代码,它会成功编译:

template <typename charT, typename traits>
char_proxy<charT, traits>& lazy_basic_string<charT, traits>::char_proxy::operator=(charT ch)
{
    return {};
}
模板
char\u proxy和lazy\u basic\u string::char\u proxy::operator=(图表ch)
{
返回{};
}
或者,如果您愿意:

template <typename charT, typename traits>
typename lazy_basic_string<charT, traits>::char_proxy& char_proxy<charT, traits>::operator=(charT ch)
{
    return{};
}
模板
typename lazy\u basic\u string::char\u proxy和char\u proxy::operator=(图表ch)
{
返回{};
}
您可能已经注意到,我只能将别名用作返回类型或访问操作符名称,但不能同时使用两者

我认为您已经在标准中发现了一些暗区,因为下面的代码在VS和GCC上也有不同的行为。它在VS 2015上编译,但不在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{};
}
模板
甲级{
B类{
B&test();
};
};
模板
使用B_alias=typename A::B;
模板
B_别名&B_别名::test()
{
返回{};
}

在本例中,在VS上,我可以使用别名访问函数名和指定返回类型。

我使用的是g++4.7。似乎不支持按模板别名定义类成员,因此最好避免使用此功能。