Why are template (non-static) member variables not

2019-07-17 07:05发布

While static member variables can be templated in C++14 this wont work:

class SomeClass
{
  public:

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

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

What are the reasons, that templates for variable members are not supported by the C++ standard since it should be possible in principle?

4条回答
Deceive 欺骗
2楼-- · 2019-07-17 07:13

When you instantiate the class you don't know how much memory it will use. Does this class contain an int and a double? What if you write

instance.var<float> = 0.2; 
instance.var<long long> = 1; 

later in your code

查看更多
时光不老,我们不散
3楼-- · 2019-07-17 07:20

has value types with known sizes. All complete types in C++ that you can create can have their sizes calculated by the compiler based only on information at or above the line of creation within that compilation unit.

In order to do what you want, either the size of instances of a class varies with every template variable ever used in any compilation unit, or the size of instances varies over time as new elements are added.

Now you can create new data based on type, but it won't be inside the class; instead, you add a map storing the data.

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

now foo.get<int>() allocates an int if it wasn't there, and if it was there gets it. Extra work would have to be done if you want to be able to copy instances.

This kind of mess emulates what you want, but its abstraction leaks (you can tell itmisn't a member variable). And it isn't really a template member variable, it just acts a bit like one.

Barring doing something like this, what you ask for is impossoble. And doing this as part of the language would be, quite frankly, a bad idea.

查看更多
Melony?
4楼-- · 2019-07-17 07:27

It cannot be possible in principle or in practice, as the other answers explain: sizeof(SomeClass) would be impossible to compute in general, and SomeClass would no longer have any predictable or sane identity, defeating the purpose of its existence.

If there are only a select few types you wish to choose from, and you wish to change the "selected" type at runtime, perhaps a variant is what you're looking for?

#include <variant>

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

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

(This requires C++17, but a Boost equivalent has been available for many, many years.)

It works because var will be as big as it needs to to store either an int or a double (plus some housekeeping), and this size is fixed no matter which "mode" your variant is in at any given time.

If you want to accept any type, you could use std::any, which is like a variant on drugs. The overhead is a little heavier, but if your requirements are really so relaxed then this can do the job.

But if you want multiple variables, have multiple variables.

查看更多
太酷不给撩
5楼-- · 2019-07-17 07:31

This would make two objects of the same type SomeClass different, rendering the class concept as we understand it in c++ useless.

Also your code sample implies that var could change type during runtime, this can be done using std::variant or std::any.

查看更多
登录 后发表回答