首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有各种构造函数签名的类的模板

具有各种构造函数签名的类的模板
EN

Stack Overflow用户
提问于 2012-04-07 03:34:49
回答 2查看 268关注 0票数 0

如何编写一个模板,将其作为参数类,其构造函数具有互斥签名?

代码语言:javascript
复制
class A
{
  A(){};
public:
  int a;
  A(int i) : a(i) {};
};

class B{
  B(){};
public:
  int a,b;
  B(int i,int j) : a(i), b(j) {};
};


template <class T> class C {
public:
  T* _t;
  C(int i[])
  {                       //???
    _t=new T(i[0]);       //if T has T(int) signature
    _t=new T(i[0],i[1]);  //if T has T(int,int) signature
  }
  ~C() {delete _t;}
};

int main()  
{ 
  int Ai[]={1,2};
  C<A> _c(Ai);  // template should work instantiated with A and B
  C<B> _c(Ai);  // 
  return 0;
}

AB的签名是固定的(不能更改为int[] )。上下文:我正在考虑一个包装器,它将接受一个(专门的)容器类型作为模板参数,例如T=vector<int>T=map<int,int>,当需要调用构造函数时,问题就出现了。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-04-07 03:40:31

使用可变模板化的构造函数:

代码语言:javascript
复制
template <typename T> struct C
{
    template <typename ...Args> C(Args &&... args)
    : _t(new T(std::forward<Args>(args)...))
    {
    }

    // ... destructor? Rule of five? Don't use pointers!!!
private:
    T * _t; // ouch!
};

用法:

代码语言:javascript
复制
C<A> x(1);
C<B> y(2, 3);

(真正的程序员当然更喜欢成员std::unique_ptr<T> _t;,它的语义没有改变,但允许您忽略所有注释。)

票数 4
EN

Stack Overflow用户

发布于 2012-05-28 09:46:04

我相信Kerrek SB的答案是部分正确的,但不完整。它的失败在于C<T>的构造函数过于泛型。也就是说,如果你只看它的构造函数声明,C<T>将从任何东西构造。直到你选择了构造函数并实例化,你才会发现不是这样。到那时已经太晚了。

具体示例:

假设C<T>有:

代码语言:javascript
复制
friend bool operator<(const C&, const C&);

现在,您想让C<T>成为map中的密钥

代码语言:javascript
复制
std::map<C<A>, int> m;
// ...
m.erase(m.begin());

这是一个错误,因为现在有两个erase重载,如下所示:

代码语言:javascript
复制
iterator  erase(const_iterator position);
size_type erase(const key_type& k);

m.begin()是一个iterator。这个iterator将同样容易地转换为const_iteratorkey_type (也就是C<A>)。

现在可以通过调用以下命令来修复此问题:

代码语言:javascript
复制
m.erase(m.cbegin());

而不是。但这只是过度泛型构造函数导致的问题的冰山一角。例如,分支到以下位置的代码:

代码语言:javascript
复制
std::is_constructible<C<A>, any type and any number of them>::value

可能会得到误报,因为上面的代码将始终返回 true。

修复方法有点混乱,但非常实用:

代码语言:javascript
复制
template<typename T>
struct C
{
    template <class ...Args,
              class = typename std::enable_if
                      <
                         std::is_constructible<T, Args...>::value
                      >::type
             >
    C(Args&& ...args)
        : _t(new T(std::forward<Args>(args)...))
    {
    }
    // ...
};

也就是说,向构造函数添加一个约束,这样如果它不能工作,它就不会被实例化。这是混乱的,丑陋的,不管怎样。也许你想用一个宏来修饰它。很好。但它使这个类可以工作,否则就是我上面提到的例子中的(以及许多其他问题,这些问题在几年的时间里往往会作为bug报告一次一个地出现)。

除了Kerrek SB关于在原始指针上使用unique_ptr<T>的好建议之外,我还想补充一下:

  1. 认为这个构造函数可能应该是explicit的,至少在实际用例表明它确实需要存储T而不是指向T的(可能是智能的)指针之前是这样的。除非您实际尝试指向基类以实现运行时polymorphism.

,否则不需要指针语义

总之:要提防过于泛型的代码,以及过于泛型的构造函数。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10048369

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档