2015-03-08 81 views
6

我已经知道,你可以使用std::enable_if使类的成员根据模板

用于为例启用(或没有)一类的方法:

template<size_t D, size_t E> 
class Field 
{ 
    ... 

    size_t offset(const std::array<float,D>& p) const 
    { 
    ... 
    } 

    template<typename TT = size_t> 
    typename std::enable_if<D!=E, TT>::type 
    offset(const std::array<float,E>& p) const 
    { 
    return offset(_projection(p)); 
    } 

    ... 
}; 

这有助于不能够调用函数无效在特定的情况下,以及消除重载错误......对我来说,这是非常好的!

我想更进一步,让我班的一些成员只在需要时才在场。这样,如果我尝试使用的反对,否则将没有启动

我会得到一个错误,我试图做

template<size_t D, size_t E> 
class Field 
{ 
    ... 

    template<typename TT = projectionFunc> 
    typename std::enable_if<D!=E, TT>::type _projection; 
} 

但是,编译器告诉我:

erreur: data member ‘_projection’ cannot be a member template 

是有什么办法实现我想要的?

+3

您可能希望更改'offsetof'的名称,以免有人在标题前包含并引发宏。 – chris 2015-03-08 19:34:07

+0

这是计划中,我只是寻找另一个不错的名字 – Amxx 2015-03-08 19:40:52

+0

这个特殊的SFINAE也有点... icky。在'D == E'的情况下,你最终得到'typename std :: enable_if :: type'。专门研究标准库类型特征是UB,所以有争议的是假设的实现可以调用“无法生成专门化”规则并将其称为不合格。 – 2015-03-08 19:44:08

回答

5

将数据成员保存在一个单独的类中,然后您可以根据需要进行专门化。

template<size_t D, size_t E> 
class Field { 
    template<size_t, size_t> struct Field_Members { 
     int _projection; 
    }; 
    template<size_t V> struct Field_Members<V, V> { }; 
    Field_Members<D, E> m; 
}; 

,然后使用m._projection

Field_Members不必是嵌套类模板;如果需要,可以将它移到外面。它也可以从Field继承,但它会成为一个依赖的基础,并且你必须编写this->_projection,所以它不会节省很多输入。

4

AFAIK,这是不可能的类模板中的一个简单的SFINAE。当然,您可以根据编译时间条件(即通过std::conditional)获得该成员的类型,但不能完全消除该成员。

可以执行的操作,当然,是使用另一个类模板,如

template<bool Condition, typename T> struct Has { T value; }; 
template<typename T> struct Has<false,T> {}; 

并声明了这种类型的构件(或碱)和经由Has<>::value访问对象:

typename<Condition> 
class foo 
{ 
    Has<Condition, double> x; // use x.value (only if Condition==true) 
};