我想让用户控制"内部类型"基类。这段代码工作正常。
版本1 (demo)
//library layer
template<class Derived> class BT_trait{
public: using type=int;
};
template<class Derived> class BT{
public: using typee=typename BT_trait<Derived>::type;
public: typee f(){ return 1;}
};
//user code below
class C;
template<> class BT_trait<C>{
public: using type=std::string; //<-- user want to set "internal type"
};
class C : public BT<C> {
public: typee f(){ return "OK";}
};
int main(){
C bt;
std::cout<< bt.f();
}
如果我通过添加模板参数使其更复杂一点,它就不再可编译了 (如下所示)
版本2 (demo)
template<class Derived> class BT_trait{
public: using type=int;
};
template<class Derived,class Dummy> class BT{
public: using typee=typename BT_trait<Derived>::type;
public: typee f(){ return 1;}
};
//user code below
template<class T> class C;
template<class T> class BT_trait<C<T>>{
public: using type=std::string;
};
template<class T> class C : public BT<C<T>,T> {
// public: typename BT<C<T>, T>::typee f(){ return "OK";} //Version #2b
public: typee f(){ return "OK";} //Version #2a
//^ error: 'typee' does not name a type; did you mean 'wctype'?
};
int main(){
C<int> bt;
std::cout<< bt.f();
}
但是如果我使用#2b
(脏)而不是#2a
(简明),上面的代码将正常工作。
为什么?是否可以使#2a
有效?
根据Specialization of template function after point of use will break the compilation的引用: -
部分[temp.expl.spec] 14.7.3p6:如果是模板,则是成员 模板或类模板的成员是明确专门的 那个专业化应该在第一次使用之前宣布 那种会导致隐式实例化的特化 地方,在发生这种用途的每个翻译单位;没有 诊断是必需的。
我怀疑我的代码是未定义的行为。正确吗?
我对模板专业化很陌生。
答案 0 :(得分:2)
请注意,typee
类型取决于模板参数。作为选项,您可以通过添加using指令使typee
可识别:
using typename BT<C<T>, T>::typee;
public: typee f(){ return "OK";}
答案 1 :(得分:2)
不,您的代码不会显示UB,甚至在编译时也不会。
问题是,一旦C
成为模板,两阶段查找规则就会开始在其中应用。基本上,在解析模板时会查找不依赖于模板参数的名称,此时T
的参数当然是未知的,因此编译器无法查看BT<C<T>, T>
并查找typee
在那里定义。所以它失败了。
您必须将typee
标记为从属名称(因为 依赖于T
)。你有几种方法:
引用时符合条件:
public: typename C::typee f(){ return "OK";}
将其带入您的课程范围(同样由VTT's answer建议):
using typename BT<C<T>, T>::typee;
public: typee f(){ return "OK";}