C++ 定义不带模板参数的成员类的类型

c++ defining type of a member class without template argument

本文关键字:参数 成员类 类型 定义 C++      更新时间:2023-10-16

我正在尝试设置类成员的类型,而不通过模板参数传递它。

详细内容:

// Forward declaration:        
class A;        
class B;
class Base
{
};    
template <class T>    
class Derived : public Base
{    
private:
T2 var;    
};

其中 T 可以是class Aclass B. 我想做的是Derived<A>T2 是 int(例如),Derived<B>T2 是双精度(例如)。我想避免以下解决方案:

template <class T1, class T2>
class Derived : public Base
{
private:
T2 var;
};

我想避免这种情况,因为对于Derived<A>T2 可能有多种可能的组合:Derived<A,int>Derived<A,double>、...

我想要的是T2的类型对于整个Derived<A>都是唯一的。

知道如何解决这个问题吗?

更新:注释显示您尝试解决的原始问题在问题中没有完全解释。尽管如此,我还是会把原始答案留在这个答案的底部。

var成员不能有两个具有不同类型 T2 的Derived<A>。此外,用户定义的变量不能影响成员变量的类型。变量值在运行时设置,类型在编译时确定。

若要存储用户以某种方式定义的类型,必须将变量限制为一组已知类型,或者使用包含变量内容的序列化版本的一种类型。已知类型的集合通常用于数据库的上下文中,其中字段可以具有几种预定义类型之一(例如字符串、整数、布尔值、双精度)。然后,成员变量的类型可以是 Boost.Variant,仅限于该类型的C++表示形式。"用户定义类型"的另一个应用是程序的用户必须以某种方式定义类型及其对象的布局和解释,例如,如果您的程序是某些脚本语言的解释器。在这种情况下,可以使用 Boost.Variant (或类似的东西),或者,由于该值可能是某个用户提供的输入,只需将序列化值存储在字符串中并在每次必须处理它时对其进行解释。

原答案:

这通常通过模板元编程来完成,在本例中为类型函数(有时,根据上下文,特征或策略类的一部分):

template <class T>
struct DerivedMemVarType {
typedef double type; //default
};
template<>
struct DerivedMemVarType<A> {
typedef int type;
};

然后:

template <class T>    
class Derived : public Base
{  
typedef typename DerivedMemVarType<T>::type T2;  
private:
T2 var;    
};

您还可以省略默认值,以便尚未在函数中映射的类型的任何Derived实例化都会给出编译错误:

template <class T>
struct DerivedMemVarType; //default is not defined
template<>
struct DerivedMemVarType<A> {
typedef int type;
};
template<>
struct DerivedMemVarType<B> {
typedef double type;
};
//...
Derived<C> dc; // ...template error mess.... 
// --> error: invalid use of incomplete type 'struct DerivedMemVarType<C>'

如果你没有任何特定于类型的函数调用,你可以使用类似...

class A;        
class B;
class Base
{
};    
template <class T>    
class Derived : public Base
{   
public:
Derived(T startVal):var(startVal){}
private:
T var;    
};
template <typename T>
Derived<T> MakeDerived(T initValue)
{
return Derived<T>(initValue);
}

现在你可以通过以下方式使用它,编译器应该知道你传递给函数的类型。

int initialValue = 0;
auto derived = MakeDerived(initialValue);

我认为你可以创建一个单独的类,它只包含一个typedef,然后你专门化并在你的派生类中使用。

template<typename T>
class VarType {
public:
typedef int TheType;
}
template <>    
class VarType<B> {    
public:
typedef double TheType;
};
template <typename T>    
class Derived : public Base {    
private:
typename VarType<T>::TheType var;    
};