类模板,成员函数定义,如果对象是X类型?

时间:2017-03-20 07:49:44

标签: c++

仅当创建的对象是特定类型时,是否可以创建具有成员函数定义的类模板?

我已经创建了一个模板类,我将用于存储int或double,但是对于双打我也希望能够设置精度(使用myclass< double>创建的对象应具有此功能,但是对于myclass< int>根本不需要存在。)

我知道我可以使用基类模板,并创建新类" myInt"," myDouble"使用它并仅在myDouble类中实现该功能,但我认为在类模板中为双精度定义功能(函数和成员变量)会更清晰,如果这可能并且更可取吗? / p>

让我们添加一个示例来展示我想要做的事情:

#include <iostream>
#include <iomanip>

class commonBase{

public:
    void setState(int state);
    virtual void print() = 0;
private:
    int _my_state;
};


template <typename T>
class generalObject : public commonBase {
public:
    void value(T value);
    void print(){ std::cout << "My value: " << _my_value << std::endl; }
private:
    T _my_value;
};


template <typename T>
void generalObject<T>::value(T value){
    _my_value = value;
}

// Is there any way do specialize only only whats different from the generalObject template?
// Here I thought I could specialize the case where a generalObject is created of <double>, but
// when I do, nothing is derived from generalObject (or at least not visible as far as I can tell)
template<>
class generalObject<double>{
public:
    void setPrecision(int precision){ _my_precision = precision; }

    // here I would like a special implementation of print(), which overrides the print() in generalObject 
    // and instead also prints according to the precision set when the object is of <double> type.
    // Row below an example which doesn't work (compiler error, _my_value undefined)
    void print(){ std::cout << "My value: " << std::setprecision(_my_precision) << _my_value << std::endl; }

private:
    int _my_precision;
};


int main(int argc, char* argv[]){

    generalObject<int> o1;
    o1.value(1);
    o1.print();
    o1.setState(1); //inherited from the commonBase

    generalObject<double> o2;
    o2.setPrecision(2);
    o2.value(2); //here value isn't available (compile error)
    o2.print();
    o2.setState(123); //also isn't available (compile error)


}

4 个答案:

答案 0 :(得分:0)

不确定

template <typename T> class Poly;
void set_precision(Poly<double>* self, int a) {};

如果你真的想要点符号,你可以添加:

template <typename T> class Poly {
  public: void set_precision(int a){::set_precision(this,a);}
  ...

但是我觉得你应该考虑一下你想要完成的事情。如果MyInt和MyDouble具有不同的字段,不同的方法和不同的实现,它们可能应该是不同的类。

答案 1 :(得分:0)

这可以使用template specialization来解决。

我们首先定义一个通用模板......

template< typename T >
struct myclass
{
    // common stuff   
};

...并专门针对double

template<>
struct myclass<double>
{
    int precision = 10;
    void setprecision( int p ){ precision = p; }
};

现在只能为setprecision()调用myclass<double>方法。如果我们尝试将其称为其他任何内容,编译器会抱怨,例如myclass<int>

int main()
{    
    myclass<double> d;
    d.setprecision( 42 );    // compiles

    myclass<int> i;
    i.setprecision( 42 );    // fails to compile, as expected
}

Demo.

答案 2 :(得分:0)

如果问题是关于成员函数,那么这是没有类模板专门化的方法之一:

#include <iostream>
#include <type_traits>

template <typename T>
struct Type {
  template <typename U = T,
            typename = typename std::enable_if<std::is_same<U, double>::value>::type>
  void only_for_double() {
    std::cout << "a doubling" << std::endl;
  }  
};

int main() {
  Type<int> n;
  Type<double> d;

// n.only_for_double(); // does not compile.
  d.only_for_double();
}

Example on ideone.com

如果您需要基于模板参数的数据成员存在,则必须进行某种特化,在这种情况下,将函数置于相应的特化中可能更简单。

编辑:在OP提出更具体的问题之后 这是一种方法,没有额外的类,摆脱虚函数。希望它有所帮助。

#include <iostream>
#include <iomanip>

template <typename T, typename Derived = void>
class commonBase {
  public:
    void setState(int state) { 
      _my_state = state;
    }
    void value(T value) {
      _my_value = value;
    }

    template <typename U = Derived,
              typename std::enable_if<std::is_same<U, void>::value,
                                      void * >::type = nullptr>
    void print() const {
      std::cout << "My value: " << _my_value << std::endl;
    }

  template <typename U = Derived,
            typename std::enable_if<!std::is_same<U, void>::value,
                                      void * >::type = nullptr>
    void print() const {
      static_cast<Derived const *>(this)->_print();
    }
  protected:
    T _my_value;
    int _my_state;
};

template <typename T>
class generalObject : public commonBase<T> {
};

template<>
class generalObject<double> : public commonBase<double, generalObject<double>> {
  private:
    friend commonBase<double, generalObject<double>>;

    void _print() const { 
      std::cout << "My value: " << std::setprecision(_my_precision) << 
                   _my_value << std::endl;
    }

  public:
    void setPrecision(int precision){ _my_precision = precision; }

private:
    int _my_precision;
};


int main(){
  generalObject<int> o1;
  o1.value(1);
  o1.print();
  o1.setState(1); 

  generalObject<double> o2;
  o2.setPrecision(2);
  o2.value(1.234);
  o2.print();
  o2.setState(123);
}

Same code on ideone.com

答案 3 :(得分:0)

仅对某些模板参数存在具有类模板成员函数的基本方法是为这些模板参数创建类模板的特化。

template<typename T>class X{
    // general definition
};

template<>class X<double>{
    // double-specific definition
};

这样做的缺点是专业化需要复制任何常见的东西。解决此问题的一种方法是将常用内容移到基类模板中:

template<typename T>class Xcommon{
    // common stuff
};
template<typename T>class X: public Xcommon<T>{
    // general definition
};

template<>class X<double>: public Xcommon<double>{
    // double-specific definition
};

或者,您可以采用另一种方式:将常用内容放在派生类中,将附加内容放在基础中,并专门化基础:

template<typename T>class Xextras{
    // empty by default
};
template<typename T>class X: public Xextras<T>{
    // common definition
};

template<>class Xextras<double>{
    // double-specific definition
};

无论哪种方式都可行;哪个更好取决于细节。

这两种方法都适用于数据成员和成员函数。

或者,您可以使用enable_if表示如果模板参数不满足所需条件,则不会通过重载决策选择成员函数。这要求成员函数本身就是一个模板。

template<typename T>class X{
    template<typename U=T> // make it a template,
    std::enable_if<std::is_same_v<U,double>> double_specific_function(){
        // do stuff
    }
};

除非别无选择,否则我不推荐此选项。