为什么C ++中不支持模板(非静态)成员变量?

时间:2018-03-20 23:29:56

标签: c++ class templates c++14

虽然静态成员变量可以在C ++ 14中模板化,但这不起作用:

class SomeClass
{
  public:

  template<typename T>
  T var = {};
};

int main()
{
  SomeClass instance;
  instance.var<int> = 50;
  instance.var<double> = 0.1;
}

C ++标准不支持变量成员模板的原因是什么,因为原则上它应该是可能的?

4 个答案:

答案 0 :(得分:2)

当您实例化课程时,您不知道它将使用多少内存。这个类是否包含int和double?如果你写

怎么办?
instance.var<float> = 0.2; 
instance.var<long long> = 1; 

稍后在您的代码中

答案 1 :(得分:2)

这将使两个相同类型SomeClass的对象不同,渲染类概念,因为我们在c ++中理解它是无用的。

此外,您的代码示例意味着var可以在运行时更改类型,这可以使用std :: variant或std :: any来完成。

答案 2 :(得分:2)

原则上或实践中不可能,正如其他答案所解释的那样:sizeof(SomeClass)一般无法计算,SomeClass将不再有任何答案可预测或理智的身份,挫败其存在的目的。

如果您只想选择几种类型,并且希望在运行时更改“选定”类型,那么您可能正在寻找变体吗?

#include <variant>

class SomeClass
{
public:
   std::variant<int, double> var = {};
};

int main()
{
   SomeClass instance;
   instance.var = 50;
   instance.var = 0.1;
}

(这个requires C++17,但很多年来都有一个Boost等价物。)

这是有效的,因为var会像存储 intdouble(加上一些内务管理)所需的那么大,而这个无论您的变体在任何给定时间处于哪种“模式”,大小都是固定的。

如果您想接受任何类型,您可以使用std::any,这就像毒品的变种一样。开销有点重,但如果您的要求真的如此放松,那么这可以完成工作。

但是如果你想要多个变量,那就有多个变量。

答案 3 :(得分:1)

包含已知大小的值类型。您可以创建的所有C ++类型的完整类型都可以由编译器根据该编译单元中创建行或其以上的信息计算其大小。

为了做你想做的事,一个类的实例大小随着任何编译单元中使用的每个模板变量而变化,或者实例的大小随着添加新元素而随时间变化。

现在您可以根据类型创建新数据,但它不会在类中;相反,你添加一个存储数据的地图。

using upvoid=std::unique_ptr<void, void(*)()>;
template<class T>
static upvoid make(){
  return { new T, [](void*ptr){ delete static_cast<T*>(ptr); } };
}
std::map<std::type_index, upvoid> m_members;
template<class T>
T& get() {
  auto it = m_members.find(typeid(T));
  if (it == m_members.end()){
    auto r = m_members.insert( {typeid(T), make<T>()} );
    it=r.first;
  }
  return *it.second;
}

现在foo.get<int>()分配int如果它不在那里,如果它在那里得到它。如果您希望能够复制实例,则必须完成额外的工作。

这种混乱模仿你想要的东西,但它的抽象泄漏(你可以告诉它不是一个成员变量)。并且它实际上不是模板成员变量,它只是有点像一个。

除非做这样的事情,否则你要求的是不可能的。坦率地说,作为语言的一部分,这样做是一个坏主意。