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

Class template, member function definition if object is of type X?

本文关键字:对象 类型 如果 成员 定义 函数      更新时间:2023-10-16

是否只有在创建的对象是特定类型时才可以使用成员函数定义创建类模板?

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

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

让我们添加一个示例来展示我想做什么:

#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)

}

当然。

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具有不同的字段,不同的方法和不同的实现,则它们应该是不同的类。

这可以使用模板专用化来解决。

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

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
}

演示。

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

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
}
};

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

如果问题是关于成员函数的,那么这里是在没有类模板专用化的情况下执行此操作的方法之一:

#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();
}

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);
}

ideone.com 上的代码相同