【问题标题】:Deduce template parameter from member variable in constructor从构造函数中的成员变量推导出模板参数
【发布时间】:2015-06-08 11:27:44
【问题描述】:

我有一个 C++ 库,它是 C 库的包装器。工厂类Creator 创建对象,每个对象代表C 库的部分功能。 这些类构造函数是私有的,以确保所有对象都是通过 Creator 类创建的,因为 C 库需要一些内部魔法(我在下面的简化示例中省略了)。

一切正常,但我有以下“问题”:

UsesAandB类中,我必须指定A<>的模板参数两次: 一次在成员声明中(std::shared_ptr<A<int>>),一次在构造函数的初始化列表中(creator->createA<int>)。

既然我已经知道成员 aInt 将是 std::shared_ptr<A<int>> 类型,我如何使用这些知识在构造函数中调用相应的 createA<int>() 方法而不重复 int 或者我如何避免调用createA<int>() 呢?

#include <memory>

class Creator;

template<typename T>
class A
{
    friend class Creator;
private:
    A(int param) {}
    T value;
};

class B
{
    friend class Creator;
private:
    B(){}
};

class Creator
{
public:
    template<typename T>
    std::shared_ptr<A<T>> createA(int param) { return std::shared_ptr<A<T>>(new A<T>(param)); }
    std::shared_ptr<B> createB() { return std::shared_ptr<B>(new B());}
};

class UsesAandB
{
public:
    UsesAandB(std::shared_ptr<Creator> creator)
        : creator(creator),
          aInt(creator->createA<int>(0)),
          aDouble(creator->createA<double>(1)),
          b(creator->createB())
   {

   }
private:
    std::shared_ptr<Creator> creator;
    std::shared_ptr<A<int>> aInt;
    std::shared_ptr<A<double>> aDouble;
    std::shared_ptr<B> b;
};

int main()
{
    auto creator = std::make_shared<Creator>();
    UsesAandB u(creator);
    return 0;
}

【问题讨论】:

  • 类 A 可以有一个 typedef (例如 A::type) 用于实例化它的类型。然后,您可以使用该 typedef。编辑:我不确定是否有可能摆脱未初始化的共享指针。 :)
  • @rozina: 并像这样使用它? aInt(creator-&gt;createA&lt;A::type&gt;(0)) ?好的,可以,但是Creator 可以使用typedef 以某种方式推断它吗?
  • 不是这样,因为 A 是一个模板,所以 A::type 不起作用。 A::type 会,但这没有任何效果:) 我会用我的想法写一个答案。虽然我怀疑你会满意:D

标签: c++ templates c++11


【解决方案1】:

要从shared_ptr 中获取类型,您需要将其传递给像这样的模板函数:

template <typename U>
shared_ptr< A<U> > CreateA( std::shared_ptr<Creator>& c,
                            const shared_ptr< A<U> >& p,
                            const U& val )
{
    return c->createA<U>(val);
}

那么简单:

aInt(CreateA(creator, aInt, 0 )),

样品在这里 - http://ideone.com/Np7f8t

【讨论】:

  • 我建议通过 const 引用传递 shared_ptr c,因为 shared_ptr 本身没有被修改(它仍然可以调用 Creator 的非常量函数)。另外,我不明白为什么你的函数不简单地修改 p 而不是返回应该用什么来构造 p。
  • @KABoissonneault 它可能是一个常量引用(同样适用于val 参数),我没有包括它,因为重点是提取类型信息的方法。我没有修改p,因为该函数在构造函数主体之前使用——它必须返回一个指针,如果它还修改了p,它将是一个做两件事的函数——这不是一个好习惯。所以p对我来说只是一个类型信息参数。
【解决方案2】:

我的想法,不知道它是否能解决任何问题,但您确实消除了在声明和构造函数调用中具有不同类型的机会。

template<typename T>
class A
{
    friend class Creator;
private:
    typedef T type;
    A(int param) {}
    T value;
};

class UsesAandB
{
typedef std::shared_ptr<A<int>> sharedA;

public:
    UsesAandB(std::shared_ptr<Creator> creator)
        : creator(creator),
          aInt(creator->createA<sharedA::element_type::type>(0)),
          aDouble(creator->createA<double>(1)),
          b(creator->createB())
   {

   }

private:
    std::shared_ptr<Creator> creator;
    sharedA aInt;
    std::shared_ptr<A<double>> aDouble;
    std::shared_ptr<B> b;
};

【讨论】:

  • 所以我必须typedefall 用例。不过,Creator 怎么能用 typedef ... type 呢?
  • @m.s.我必须说这超出了我的知识范围。如果typdef 可以被模板化,那么我可以为std::shared_ptr&lt;A&lt;T&gt;&gt; in Creator 制作typedef。 Ofc 你可以将Creator 设为模板类,然后它就可以工作了。
  • @m.s.虽然我不确定你为什么不想Creator 使用typedef ... type?您的问题表明您想使用UsesAandB 中的知识而不是Creator 中的知识。
  • 理想情况下,我只需要指定一次类型(在声明成员变量时),然后一个`UsesAandB`会自动将类型传递给Creator,而无需再次关心它
【解决方案3】:

您可以添加以下静态模板函数

template <class T>
static std::shared_ptr<T> create1(std::shared_ptr<Creator> &creator, std::shared_ptr<T> &,T value)
{
   return creator->createA(value) ;
}

然后像这样初始化:

UsesAandB(std::shared_ptr<Creator> creator)
        : creator(creator),
          aInt(create1((creator, aInt, 0)),
          aDouble(create1(creator, aDouble, 1)),
          b(creator->createB())
   {

   }

create1 只需要共享指针来推断正确的类型。 一个问题是这段代码应该引发一个警告(这在初始化列表中使用)

【讨论】:

  • 操作,我忘记插入通话了。
猜你喜欢
  • 2015-05-09
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
  • 1970-01-01
  • 1970-01-01
  • 2011-10-21
  • 1970-01-01
  • 2019-01-29
相关资源
最近更新 更多