【问题标题】:Is there a way to define a template member in a non-template class?有没有办法在非模板类中定义模板成员?
【发布时间】:2019-08-16 20:46:07
【问题描述】:

假设我有一个名为 Compute 的类模板,以及另一个名为 Function_A 的类,并带有一个成员函数模板:

template <typename T> void Evaluate(T parameter)

我只能按原样使用Function_A 类。我已经知道T只能是type_1type_2这两种类型之一。

有没有办法将类似于Compute&lt;T&gt; C 的东西作为Function_A 的成员变量,而不是在Evaluate(...) 内定义一个本地Compute&lt;T&gt; 对象?我知道这违反了使用模板的理念,因此这可能是不可能的,但理想情况下可以这样做吗?

我试图在Function_A 中拥有两个成员Compute&lt;type_1&gt; C1Compute&lt;type_2&gt; C2,然后在if (typeid(T) == typeid(type_1)) 下使用它们,但这很可怕,也违反了使用模板的理念。

只是为了说明我的意思:

template <class T>
class Compute
{
public:
  T Function_B(T parameter)
    {
      return f.eval(parameter);
    }

private:
  SomeClass<T> f;
}

还有一个班级:

class Function_A
{
  public:
    template <typename T> T Evaluate(T parameter)
    {
      Compute<T> C; //this is very expensive!
      T value = C.Function_B(parameter);
      return value;
    }

  private:
    double SomeParameter;
    //Compute<T> C; //conceptually what I want
}

【问题讨论】:

    标签: c++ class templates


    【解决方案1】:

    怎么样(未经测试):

    class Function_A
    {
      public:
        template <typename T> void Evaluate(T parameter)
        {
          T value = std::get<Compute<T>>(computers).Function_B(parameter);
          return T(SomeParameter) * value;
        }
    
      private:
        double SomeParameter;
        std::tuple<Compute<type_1>, Compute<type_2>> computers;
    };
    

    注意:std::pair 的工作方式与此处的 std::tuple 完全相同,如果您喜欢它添加的第一个/第二个语义。

    另外,请注意 T(SomeParameter) 是 C 风格的转换,如果 T 不是类类型,这可能会出现问题。考虑T{}static_cast&lt;T&gt;()

    【讨论】:

    • 测试与否,我喜欢使用标准库来解决这个问题
    • @StoryTeller 当然,我不是野蛮人 :)
    • 为什么要使用std::tuple 而不是std::pair(后者也支持get)?我同意std::tuple 原则上符合设计(没有什么是特定于只有两种类型的),但我觉得值得讨论。
    • @MaxLanghof 好吧,你说的。就问题而言,那里没有固有的“第一”或“第二”,所以tuple它是。
    • 哦,使用static_cast 会比T(SomeParameter) 更好。我一直试图弄清楚你要取消引用的指针是什么。
    【解决方案2】:

    您可以做的一件事是制作C static。如果你有

    template <typename T> void Evaluate(T parameter)
    {
      static Compute<T> C; // only do this once per T now
      T value = C.Function_B(parameter);
      return T(SomeParameter)*value;
    }
    

    然后,当您使用 type_1 调用 Evaluate 时,您将拥有一个包含 C&lt;type_1&gt; 的函数版本,该版本仅在第一次调用该函数时构建,同样的事情发生在 @987654327 @。

    【讨论】:

    • 请记住,您必须考虑使用此解决方案的共享状态和线程安全性。每个Evaluate&lt;T&gt; 调用,即使来自不同的Function_A 对象,都将使用相同的Compute&lt;T&gt; 对象。
    • @Kevin 在每个对象级别上也是如此,因为 Compute&lt;T&gt; 作为成员,这是 OP 最初想要的
    • @user463035818 在这种情况下,每个Function_A 对象都有自己的Compute&lt;T&gt;。这里只有 1 个 Compute&lt;T&gt;(每个 T)在所有 Function_A 对象之间共享。不一定是问题,但需要考虑。
    • @user463035818 虽然在这种情况下,您可以通过为每个线程设置不同的Function_A 来缓解问题。我的解决方案强制所有线程共享一个对象,因此需要考虑。
    • 此解决方案开箱即用,请参阅我上面的评论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-28
    • 2017-10-20
    • 2012-11-03
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    相关资源
    最近更新 更多