【问题标题】:Why are template (non-static) member variables not supported in C++?为什么 C++ 不支持模板(非静态)成员变量?
【发布时间】:2018-03-20 23:29:56
【问题描述】:

虽然静态成员变量可以在 C++14 中进行模板化,但这是行不通的:

class SomeClass
{
  public:

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

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

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

【问题讨论】:

  • sizeof(SomeClass) 是什么?
  • @tkausl sizeof(SomeClass) = 所有实例化的模板成员变量和非模板成员的大小之和
  • @DariusDuesentrieb:这将要求需要知道sizeof(SomeClass) 的每一段代码也需要知道在其众多配置中的任何一个中使用SomeClass 的每一段代码。这是棘手的。在一般情况下,我无法想到一种方法。

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


【解决方案1】:

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

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

稍后在您的代码中

【讨论】:

    【解决方案2】:

    这会使 SomeClass 相同类型的两个对象不同,从而使我们在 c++ 中理解的类概念变得无用。

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

    【讨论】:

      【解决方案3】:

      不可能在原则上或实践中是可能的,正如其他答案所解释的那样:sizeof(SomeClass) 通常无法计算,SomeClass 将不再具有任何可预测或理智的身份,违背了它存在的目的。

      如果您只希望从少数几个类型中进行选择,并且希望在运行时更改“选定”类型,那么 variant 可能就是您正在寻找的? p>

      #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 (加上一些内务管理)所需的一样大,并且无论哪个大小都是固定的您的变体在任何给定时间都处于“模式”。

      如果你想接受 any 类型,你可以使用std::any,这就像药物的变种。开销有点重,但如果您的要求真的如此轻松,那么这可以完成这项工作。

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

      【讨论】:

        【解决方案4】:

        具有已知大小的值类型。您可以在 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&lt;int&gt;() 分配一个int,如果它不存在,如果它存在则获取它。如果您希望能够复制实例,则必须完成额外的工作。

        这种混乱模拟了你想要的,但它的抽象泄漏(你可以告诉它不是一个成员变量)。而且它并不是一个真正的模板成员变量,它只是有点像一个。

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

        【讨论】:

        • @darius 是的,错字。
        • 我看了 Herb Sutter 的这个演讲,他谈到了元编程:youtube.com/watch?v=4AfRAVcThyA&t=19m11s 有没有可能用这样的东西有效地创建模板成员变量?:pastebin.com/PEfFuZmZ
        • @DariusDuesentrieb 我不确定元编程的功能性如何。具有副作用的元编程(您可以修改未返回的类型)可能能够枚举用于给定类型的所有Ts,并将它们“追溯地”添加为成员变量;功能(纯)元编程则更少。我无法确定任何事情。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-06
        • 1970-01-01
        相关资源
        最近更新 更多