C++ 基于其他数据成员的类数据成员类型?

C++ 基于其他数据成员的类数据成员类型?,c++,class,templates,c++11,C++,Class,Templates,C++11,假设我有一个基类foo和两个派生类a和B。然后我有另一个类bar,它有一个数据成员x,y,z,可以是a,或者,但是类型取决于其他数据成员x_类型,y_类型,以及z_类型,这些值在编译时不可用。我考虑过如何使用模板数据成员并在构造函数中定义类型,在构造函数中我可以得到类型的值,但显然这至少在C++11中是不可能的。那么如何进行呢 class foo{ public: foo(double); int x_type; virtual double do_something(double,

假设我有一个基类
foo
和两个派生类
a
B
。然后我有另一个类
bar
,它有一个数据成员
x
y
z
,可以是
a
,或者,但是类型取决于其他数据成员
x_类型
y_类型
,以及
z_类型
,这些值在编译时不可用。我考虑过如何使用模板数据成员并在构造函数中定义类型,在构造函数中我可以得到类型的值,但显然这至少在C++11中是不可能的。那么如何进行呢

class foo{
public:
  foo(double);
  int x_type;
  virtual double do_something(double, int) = 0;
};

class A: public foo {
public:
  A(double, double);
  double do_something(double, int);

private:
  double z1;
  double z2;
};

class B: public foo {
public:
  B(double);
  double do_something(double, int);

private:
  double w;
};

class bar {
public:
  bar();
  double do_something2(int);

private:
  int x_type;
  int y_type;
  int x_type;
  x; // these are either A or B...
  y;
  z;
};
在构造器中,我会有

if(x_type == 1){
  x = A(arg1, arg2);
} else {
  x = B(arg3);
}

在我的实际应用程序中,具有未知类型的派生类和数据成员的数量可能要多得多。我想知道是否有可能使
bar
成为具有多个模板参数的模板类,但我不确定这是否可行,因为参数类型取决于另一个参数?

您需要使用多态性并利用公共基类Foo:

private:
  int x_type;
  int y_type;
  int x_type;
  std::unique_ptr<Foo> x; // these are either A or B...
  std::unique_ptr<Foo> y;
  std::unique_ptr<Foo> z;

};

在所谓的“工厂”类或函数中移动创建正确Foo实例的代码是一种很好的做法,以隐藏决策逻辑和构造细节(有时可能非常复杂)。

编译时必须知道所有变量的静态类型,因此,它不能基于运行时对象的值进行更改。执行此操作的方法是使
x
y
z
都具有类型
std::uniqe_ptr
,然后在运行时动态分配
A
B
对象:

class bar {
public:
    bar(some_type something) {
        if (something == some_value) {
            b.x = new A(3.14, 12.34);
        } else {
            b.x = new B(456.78);
        }
    }
private:
    int x_type;
    std::unique_ptr<foo> x;
    //...
};

int main() {
    bar b(whatever());
}
类栏{
公众:
条形图(有些东西){
如果(某物==某个值){
b、 x=新的A(3.14,12.34);
}否则{
b、 x=新的b(456.78);
}
}
私人:
int x_型;
std::唯一的ptr x;
//...
};
int main(){
b条(无论什么());
}
在这种情况下,还应该将
foo::~foo()
声明为虚拟对象,以确保正确销毁派生对象

这通常也是个好主意™ 要完全消除
x\u类型
和朋友,并在创建
x
后编写与实际类型无关的代码

我想知道是否有可能使bar成为具有多个模板参数的模板类,但我不确定这是否可行,因为参数类型依赖于另一个参数

我不知道这是否有用,但我会把它放在这里以防万一

你看,模板的不同专门化可以从不同的类继承。这样您就可以:

// fwd decl
template <int kind> class bar;

template <> class bar<1> : public A {
public:
  bar(double x, double y) : A(x,y) { }
};

template <> class bar<2> : public B {
public:
  bar(double a) : B(a) { }
};
我想到了如何使用模板数据成员和在中定义类型 构造函数,我从中获取类型的值,但显然 至少在C++11中是不可能的

C++11附带了一个标准模式,通过使用
make.*
template函数创建适当类型的对象,根据一些参数处理模板化构造。请参见例如
make\u tuple
函数:

auto t = std::make_tuple(1, "abc", 1.0); 
// decltype(t) == std::tuple<int, char const*, double>
template <class T>
struct foo { 
   T t; 
   foo(T t): t(t) { }  
};

template <class T>
foo<T> make_foo(T t) { return foo<T>(t); }
auto t=std::make_tuple(1,“abc”,1.0);
//decltype(t)==std::tuple
这可以通过创建模板类和模板构造功能来实现:

auto t = std::make_tuple(1, "abc", 1.0); 
// decltype(t) == std::tuple<int, char const*, double>
template <class T>
struct foo { 
   T t; 
   foo(T t): t(t) { }  
};

template <class T>
foo<T> make_foo(T t) { return foo<T>(t); }
模板
结构foo{
T;
foo(T):T(T){}
};
模板
foo make_foo(T){return foo(T);}

如果可以用于
x
y
z
的所有类型都是从一个公共基类派生出来的,那么带有
std::unique_ptr
(+1表示Lyubomir Stankov)的基指针解决方案是一个很好的解决方案

但您询问“是否可以使bar成为具有多个模板参数的模板类”

是的,这是可能的。不是很优雅,但可能

为了好玩,我提出了以下解决方案,但我认为,在更一般的情况下(注意,在我的示例中,
a
B
是不相关的类,而不是从
foo
派生的),可能有用(我希望如此)

并定义
is
mis
如下

  template <std::size_t ... Is>
     using is = indexSeq<Is...>;

  template <std::size_t N>
     using mis = typename indexSeqHelper<N>::type;
模板
使用is=indexSeq;
模板
使用mis=typename索引seqhelper::type;

通过整数值枚举类型是一件坏事™ 反模式。这可能对应于带有指向多态类
foo
的指针的设计。然后应该有一个虚拟析构函数。
template <std::size_t ...>
struct indexSeq
 { };

template <std::size_t N, std::size_t ... Next>
struct indexSeqHelper
 { using type = typename indexSeqHelper<N-1U, N-1U, Next ... >::type; };

template <std::size_t ... Next >
struct indexSeqHelper<0U, Next ... >
 { using type = indexSeq<Next ... >; };
  template <std::size_t ... Is>
     using is = indexSeq<Is...>;

  template <std::size_t N>
     using mis = typename indexSeqHelper<N>::type;