【问题标题】:Named Constructor Idiom and Templates?命名构造函数成语和模板?
【发布时间】:2011-07-13 02:06:07
【问题描述】:

有没有办法以“漂亮”的方式将Named Constructor Idiom 与模板一起使用?

例如:

#include <vector>
using namespace std;

template< typename T >
class Foo
{
public:
    static Foo Copy(const T& arg)
    {
        Foo ret;
        ret.t_copy = arg;
        return ret;
    }

    static Foo CopyClear(const T& arg)
    {
        Foo ret;
        ret.t_copy = arg;
        ret.t_copy.clear();
        return ret;
    }

private:
    T t_copy;
};


int main( int argc, char** argv )
{
    vector<double> vec;
    vec.push_back(1);

    // #1: won't compile
    Foo< vector<double> > a_foo = Foo::CopyClear( vec );

    // #2: ugly, but works
    Foo< vector<double> > a_foo = Foo< vector<double> >::CopyClear( vec );

    return 0;
}

我想以某种方式使用#1 的语法。 #2 有效,但我的 DRY 感觉不对。

编辑:Foo 的新的、更“现实”的版本。

EDIT2:恐怕我没有 C++0x/C++1x :(

【问题讨论】:

  • #2 在哪里,或者您指的是 rvalue 正确范围的调用,它没有歧义?您是否考虑过更优雅的解决方案,例如将大小传递给构造函数?
  • 在 cmets 中,我将 CopyClear() 的第二次调用标记为 #2。

标签: c++ templates constructor


【解决方案1】:

更新答案

如果我正确理解您的意图,这将解决问题:

template< typename T >
class Foo
{
private:
    friend class FooHelper;
    size_t sz;
};

class FooHelper
{
public:
    template< typename T >
    static Foo<T> Size(const T& arg)
    {
        Foo<T> ret;
        ret.sz = arg.size();
        return ret;
    }

    template< typename T >
    static Foo<T> HalfSize(const T& arg)
    {
        Foo<T> ret;
        ret.sz = arg.size() / 2;
        return ret;
    }
};

然后编译:

int main( int argc, char** argv )
{
    vector<double> vec;
    vec.push_back(1);

    Foo<vector<double>> a_foo = FooHelper::HalfSize( vec );
}

【讨论】:

  • 对给定的示例有效,但是,我猜 OP 想在他的类中使用 T,而不是 only 构造函数。另外,我不知道实际问题的任何解决方案,所以它可能确实不可能按照你想要的方式(我可能弄错了)。
  • @dialer, @genpfault:在这种情况下,他可以创建一个template&lt;T&gt; class Bar 并实例化它的对象以从Foo 静态方法返回。实际上,这会带来重复模板参数类型的问题,但在这种情况下,它将在 Foo 内重复 T(可以被认为是“库代码”)。无论如何,如果 OP 提供更多信息,我们可以调整我们的答案。
  • @genpfault:我根据上次评论更新了答案。请看看它是否适合您。
【解决方案2】:

我不认为存在 DRY 问题,将其视为语言限制。 如果您有一个没有模板的 Foo 类,但您想从静态方法创建一个新对象,您必须执行以下操作:

Foo a_foo = Foo::HalfSize(something);

当然还有 Foo 重复了两次。

所以,既然这里的类全名是Foo&lt; vector&lt;double&gt; &gt;,那么从Foo&lt; vector&lt;double&gt; &gt;::HalfSize() 获取静态方法是合乎逻辑的,因为那是C++ 方式。

【讨论】:

    【解决方案3】:

    除了@Jon 的回答,如果您需要将类本身作为模板,请参阅std::make_pair 及其与std::pair 的关系。

    【讨论】:

    • 还有make_sharedshared_ptr。我认为使用模板函数创建模板对象以从类型推导中受益是一种习惯用法。
    【解决方案4】:

    这在技术上是可以的,并且可能是您end问题的最简单答案:

        Foo< vector<double> > a_foo = a_foo.CopyClear( vec );
    

    技术上没问题,因为 CopyClearstatic 成员函数。

    并且没有技术问题,例如您可以改用typedef。或者只是将那些 static 成员函数放在命名空间范围内,作为函数模板。或者在某个助手类中,正如有人已经建议的那样。

    但即使没有技术问题,设计也不尽如人意;说白了(对不起),比无意义还差一点。

    例如,在CopyClear,为什么要复制一个向量然后丢弃复制结果?您只需要创建一个您的代码知道的类型的空向量。

    例如,您为什么要引入副作用机制?

    副作用是要避免和消除,而不是引入。

    干杯,

    【讨论】:

      【解决方案5】:

      如果您可以使用 C++0x 功能,auto 关键字会有所帮助。 Size()HalfSize() 是否有理由成为静态方法?如果您提供改变 sz 的方法,您可以这样做:

      template<class T>
      Foo<T> HalfSize(const T& arg)
      {
          Foo<T> ret;
          ret.setSz(arg.size() / 2); // or similar
          return ret;
      }
      

      然后#1更容易实现。

      【讨论】:

      • 恐怕我没有 C++0x :(
      【解决方案6】:

      C++1x 的救援:

      auto a_foo = Foo::HalfSize<vector<double>>( vec );
      

      而且,是的,两个关闭的&gt;&gt; 在 C++1x 中被解析为&gt; &gt;

      您附近的编译器可能已经可以使用。

      【讨论】:

      • 恐怕我没有 C++1x :(
      • @genpfault: 你用的是什么编译器?
      • @genpfault:啊,那你得切换到下一个版本。 VS2010 可以做到这一点。
      猜你喜欢
      • 1970-01-01
      • 2018-04-30
      • 1970-01-01
      • 2016-09-12
      • 2012-06-11
      • 1970-01-01
      • 2019-10-08
      • 1970-01-01
      相关资源
      最近更新 更多