在基类= undefine行为之后特化type_trait?

时间:2018-01-08 07:50:56

标签: c++ c++14 language-lawyer template-specialization typetraits

我想让用户控制"内部类型"基类。这段代码工作正常。

版本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:如果是模板,则是成员   模板或类模板的成员是明确专门的   那个专业化应该在第一次使用之前宣布   那种会导致隐式实例化的特化   地方,在发生这种用途的每个翻译单位;没有   诊断是必需的。

我怀疑我的代码是未定义的行为。正确吗?
我对模板专业化很陌生。

2 个答案:

答案 0 :(得分:2)

请注意,typee类型取决于模板参数。作为选项,您可以通过添加using指令使typee可识别:

using typename BT<C<T>, T>::typee;
public: typee f(){ return "OK";}

online compiler

答案 1 :(得分:2)

不,您的代码不会显示UB,甚至在编译时也不会。

问题是,一旦C成为模板,两阶段查找规则就会开始在其中应用。基本上,在解析模板时会查找不依赖于模板参数的名称,此时T的参数当然是未知的,因此编译器无法查看BT<C<T>, T>并查找typee在那里定义。所以它失败了。

您必须将typee标记为从属名称(因为 依赖于T)。你有几种方法:

  • 引用时符合条件:

    public: typename C::typee f(){ return "OK";}
    

    [Live example]

  • 将其带入您的课程范围(同样由VTT's answer建议):

    using typename BT<C<T>, T>::typee;
    public: typee f(){ return "OK";}