【问题标题】:C++ Templates with unique static members具有唯一静态成员的 C++ 模板
【发布时间】:2012-08-23 13:21:01
【问题描述】:

模板类的所有静态成员都为它的每个实例复制。如果我想要一个对所有实例只存在一次的静态成员,我该怎么办?在类模板之外使用普通的静态字段?会工作,但似乎不优雅,因为没有更多与模板类的关联。有没有办法以某种方式将这种独特的静态成员与模板类相关联?

【问题讨论】:

    标签: c++ templates static-members


    【解决方案1】:

    没有;每个模板类都是一个完全独立的对象。

    你可以做的是用静态成员创建一个共同的祖先类:

    class Parent
    {
    public:
      static int commonStatic;
    };
    
    template <typename T>
    class MyTempl : public Parent
    {
      static int nonSharedStatic;
    };
    

    【讨论】:

    • 你是在建议使用继承来共享一个变量,对吧?
    • @LuchianGrigore - OP 希望在模板类的所有特化之间共享一个变量,但与这些类相关联。在我的脑海中,你也许可以通过命名空间或继承来做到这一点;我看不到另一种方式。你有一个想法吗?
    • 我不明白为什么它必须与课程相关联。这些类是完全独立的,将单个变量绑定到多个类是没有意义的(从逻辑的角度来看)。
    • 我不明白为什么它不应该与类绑定。假设 MyTempl 实际上是 MyList;而Parent实际上是MyList。那么很明显 MyList "is-a" MyList,我可能想知道我总共有多少个 MyList。
    • @LuchianGrigore 我认为您对逻辑的断言不正确。 basic_ios&lt;CharT, CharTraitsT&gt; 是一个完美的例子,说明如何从一个通用的非模板基 (std::ios_base) 继承是有意义的。他们主要共享所有格式标志常量。用户不在乎他们也可以做std::ios_base::hex。他们可以做到ostream::hex,因为这是他们在使用cout 时所面临的课程。
    【解决方案2】:

    一个模板类的所有静态成员都为它的每个实例复制。

    不。每个专业化都有不同的静态,但不同的专业化是不同的类。别搞错了,vector&lt;int&gt;vector&lt;char&gt;完全分开的。把它想象成写IntVectorCharVector

    编辑:不要为此使用继承。仅仅为了共享静态成员而引入基类绝对是错误的做法。

    如果您希望在不同的班级之间共享内容,请像往常一样进行。在第三个类中包装一些静态变量,就是这样。

    【讨论】:

    • 虽然您是绝对正确的,但请注意您没有回答 OP 的问题(他们显然是指专业化)。
    • 我知道,但他们仍然可以共享一些便利成员。静态成员无论如何都不会假设是一个类,所以我不必关心 vector 和 vector 是否是相关的类。
    • @gexicide 你想达到什么目的?
    • 例如,一个静态成员对于所有特化都是相同的(因此,复制它会浪费空间)
    • “在第三个类中包装一些静态数据,就是这样”。我不明白这是一个解决方案。他将无法通过“vector::myStaticMember”访问它。继承似乎很好地解决了它。你能指出究竟是什么“绝对是错误的方式”吗?
    【解决方案3】:

    为模板类定义一些基类。在这个基类中包含所有常见的成员:

    class ExampleBase {
    public:
       static int foo;
    };
    int ExampleBase::foo = 0;
    
    template <class A>
    class Example : private ExampleBase {
    public:
        static void setFoo(int f) { foo = f; }
        static int getFoo() { return foo; }
    };
    

    那么每个 Example 实例都有共同的静态成员ExampleBase::foo

    int main() {
        Example<int>::setFoo(7);
        assert(Example<float>::getFoo() == 7);
    };
    

    【讨论】:

    • 为什么需要从ExampleBase派生?为什么不按原样使用它?
    • @Luchian 我不明白你。据我了解的问题,对于给定模板的所有模板实例的所有对象实例,都需要公共静态成员。我不知道其他解决方案。请举个例子?请参阅我对答案的更新。
    • 我的意思是你可以通过 ExampleBase::foo 访问 foo 而不从它派生。 &问题本身就是错误的。建议一个更好的设计,而不是建议一个导致严重设计缺陷的解决方案。
    • @Luchian 好的 - 我明白你的意思。来看看我的下一次更新。很明显,使用基类是必要的。我不认为这样的设计是错误的。典型用法是计算 Example 的所有现有实例,而不考虑 T。
    【解决方案4】:

    在某处放置一个全局变量。

    类似这样的:

    #include <iostream>
    
    // header.hpp
    extern int someValue;
    template< typename T >
    struct A
    {
      int foo() const
      {
        return someValue;
      }
    };
    
    // source.cpp
    int someValue = 5;
    
    int main()
    {
      std::cout << A< float >().foo() << std::endl;
      std::cout << A< int >().foo() << std::endl;
    }
    

    【讨论】:

      【解决方案5】:

      在类模板之外使用普通的静态字段?

      完全正确;只需将其放入模板声明之外的函数中即可。

      如果真的想在这种情况下限制访问,你可以使用这样的东西:

      class t_shared {
          static int& Shared() {
              static int s(0);
              return s;
          }
      public:
          template < typename T >
          class t_template {
          public:
              void f() {
                  std::cout << ++Shared() << std::endl;
              }
          };
      };
      
      int main(int argc, const char* argv[]) {
          t_shared::t_template<int>().f();
          return 0;
      }
      

      【讨论】:

      • 我们为什么不将 t_template 定义为 t_shared 的朋友以避免不必要的作用域?
      【解决方案6】:

      类模板在静态成员方面实际上与普通类有点不同。即使每个翻译单元都包含foo.hpp,以下内容也很好:

      foo.hpp:

      template <typename T> struct TmplFoo
      {
          static double d;
      };
      
      struct OrdFoo
      {
          static double e;
      }
      

      foo.cpp:

      #include "foo.hpp"
      
      double OrdFoo::e = -1.5;
      

      请注意,我们从不需要单独定义TmplFoo&lt;T&gt;::d。链接器知道如何确定所有对TmplFoo&lt;T&gt;::d 的本地引用(对于给定的T)都指向同一个对象。

      【讨论】:

        猜你喜欢
        • 2013-05-11
        • 1970-01-01
        • 1970-01-01
        • 2011-08-15
        • 1970-01-01
        • 2017-07-02
        • 2017-10-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多