无法定义依赖类型定义的成员
Cannot define member of dependent 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);
}
然后我想在类声明之外定义这些方法。
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_proxy
所以我无法弄清楚这里有什么问题。为什么编译器不能使用快捷方式char_proxy而不是lazy_basic_string::char_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?
有趣的是,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??
你用的是什么编译器?在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 {};
}
或者,如果您愿意:
template <typename charT, typename traits>
typename lazy_basic_string<charT, traits>::char_proxy& char_proxy<charT, traits>::operator=(charT ch)
{
return{};
}
正如您可能已经注意到的,我只能将别名用作返回类型或访问运算符名称,但不能同时使用两者。
我想你已经在标准中找到了某种暗区,因为下面的代码在 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{};
}
在这种情况下,在 VS 上,我能够使用别名来访问函数名称和指定返回类型。
- 为什么我不能在一个类的不同行中声明和定义成员变量?
- C++令牌定义成员
- 在没有类定义的标头中定义成员变量
- 如何在类的构造函数中定义成员向量的大小
- 如何在C++中动态定义成员函数
- C++ Boost.Serialization - 用户定义成员的非侵入式序列化
- C++类 - 使用公共变量并在类外定义成员函数
- G++ - 对已定义成员函数的未定义引用
- 在哪里以及如何定义成员变量?在头文件还是实现文件中?
- 是否可以修改STL并自定义成员函数
- 从 boost::mpl:vector 类型列表中定义成员变量
- 在构造对象时定义成员函数
- 为什么定义成员函数指针变量需要类名
- 复制构造函数中的 C++ 用户定义成员
- 如何根据类参数定义成员类运算符
- 使用指向未定义成员函数的指针时的未定义引用
- 如何在运行时定义成员数组大小
- C++-在模板类之外但在头中定义成员函数
- c++在不知道对象类型的情况下定义成员函数指针
- 在特定偏移量中定义成员的结构