MI和隐式复制构造函数的错误(是:在什么条件下,模板可以是复制构造函数?) [英] MI and implicit copy constructor bug (was: Under what conditions can a template be the copy constructor?)

查看:102
本文介绍了MI和隐式复制构造函数的错误(是:在什么条件下,模板可以是复制构造函数?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很确定这个问题的答案是从不,模板可以是复制构造函数。



不幸的是,我只花了3小时找出为什么我得到一个关于递归的警告,跟踪到复制构造函数,看着调试器疯了,不让我看看递归代码,最后跟踪到一个基本构造函数中缺少'&'。



你看,我有一个复杂的基于策略的设计主机,已经工作好一段时间了。我去了覆盖两个策略在一个,并遇到一个递归复制构造函数。将它缩小到一个策略,需要提供一个构造函数,可以采用一种类型的XXX概念作为其参数,但在这种情况下,我只是抛弃它。所以我写了

  struct my_policy 
{
template<类型名T>
my_polity(T const){} // missing'&'... oops
};

现在,my_policy是主机的基类(当然),这个小的类型引起递归,主机的复制构造函数将链向上传递给模板化构造函数,而不是隐式的编译器生成的复制构造函数。然后它当然会再次调用其复制构造函数来创建临时的。



真正令人着迷的是,我不能在简化的代码中重新创建它。即使有一个模拟政策主机的例子,我不能让它发生。以下代码不会出现此问题:

  #include< boost / utility / enable_if.hpp> 
#include< boost / mpl / bool.hpp>

struct base
{
template<类型名T>
base(T const){}
};

struct another_base
{
int x;

another_base(int y):x(y){}
};

template<类型名T>
struct is_derived:boost :: mpl :: false_ {};

template<类型名T1,类型名T2>
struct derived:T1,T2
{
template<类型名T>
derived(T const& x,typename boost :: disable_if< is_derived< T>> :: type * = 0):T1(0),T2(x){}
}

template<类型名T1,类型名T2>
struct is_derived< derived< T1,T2>> :boost :: mpl :: true_ {};

int main()
{
derived< base,another_base> d(23);
derived< base,another_base> x = d;
}



我使用boost的参数库来使主机的7个参数可通过名称访问。也许这是问题,我不知道。无论如何,我想知道是否有人知道什么特定的条件,如果有的话,可能会导致编译器合法使用模板化的构造函数为base作为复制构造函数或从隐式复制构造函数为派生。



编辑备注:



another_base一个显式复制构造函数:

  struct another_base 
{
int x;

another_base(another_base const& b):x(b.x){}

another_base(int y):x(y){}
}

开始总结这是一个编译器错误,除非有人能告诉我为什么这是合法的。 p>

详细信息:

  

struct base
{
base(){}

private:
base(derived const&
};

struct base2
{
base2(){}
// base2(base2 const&){}
};

struct derived:base,base2 {};

int main()
{
派生d1; (d2)。
}



查看更多Schaub的答案我上面的代码并编译。它编译就好了,直到你取消注释base2的复制构造函数声明。然后它会爆炸的方式,我假设是预期与原始代码(无法访问私人构造函数在基地)。所以模板甚至不是问题的一部分;你可以重建没有他们的问题。看起来这是一个MI问题,VS一直是一个慢的正确。



我改变了标签以反映这一发现。



张贴到MS的错误库中



http://connect.microsoft.com/VisualStudio/反馈/详情/ 587787 / implicit-copy-constructor-calls-base-with-derived-type-under-specific-conditions



解决方案

我很肯定你的问题的答案是从不。



ANSI C ++标准的第12.8.2节说:


类的非模板构造函数X
是一个 copy 构造函数,如果它的第一个
参数是类型X& const X&
volatile X&或者const volatile X&,
没有其他参数
或者所有其他参数都有
默认参数。


Section 12.8.3说



类X的构造函数的声明是ill-如果它的第一个
参数是类型(可选
cv-qualified)X,并且有
没有其他参数,或者所有其他
参数都有默认参数。 A
成员函数模板永远不会
被实例化来执行将
类对象复制到其类
类型的对象。 [示例:




  struct S {
template< typename T& S(T);
};

S f();

无效的g(){
S a(f()); //不实例化成员模板
}




end example]



I was pretty sure that the answer to that question was, "Never, ever can a template be the copy constructor."

Unfortunately, I just spent 3 hours figuring out why I was getting a warning about recursion, tracked it to the copy constructor, watched the debugger go insane and not let me look at the recursive code, and finally tracked it down to a missing '&' in a base constructor.

You see, I have this complex policy-based design host that's been working fine for a while now. I went about overriding two policies in one and ran into a recursive copy constructor. Narrowed it down to one policy that is required to provide a constructor that can take a type of XXX concept as its argument, but in this case I'm just discarding it. So I wrote

struct my_policy
{
  template < typename T >
  my_polity(T const) {} // missing '&'...oops
};

Now, my_policy is a base class to the host (of course) and this little typo caused recursion where the host's copy constructor passed itself up the chain to this, templated constructor rather than an implicit, compiler generated copy constructor. It would then of course call its copy constructor again to create the temporary.

The truly fascinating thing is that I can't recreate this in simplified code. Even with a sort of mock policy host example I can't make it happen. The following code does not exhibit the issue:

#include <boost/utility/enable_if.hpp>
#include <boost/mpl/bool.hpp>

struct base
{
  template < typename T >
  base(T const) {}
};

struct another_base 
{
  int x;

  another_base(int y) : x(y) {}
};

template < typename T >
struct is_derived : boost::mpl::false_ {};

template < typename T1, typename T2 >
struct derived : T1, T2
{
  template < typename T >
  derived(T const& x, typename boost::disable_if< is_derived<T> >::type * = 0) : T1(0), T2(x) {}
};

template < typename T1, typename T2 >
struct is_derived<derived<T1,T2>> : boost::mpl::true_ {};

int main() 
{
  derived<base, another_base> d(23);
  derived<base, another_base> x = d;
}

I am using boost's parameter library to make the 7 or so arguments to the host accessible by "name". Maybe that's the issue, I don't know. At any rate, I'm wondering if someone out there knows what specific conditions, if any, could cause a compiler to legitimately use the templated constructor for "base" as a copy constructor or from the implicit copy constructor for "derived".

Edit note:

I recreated the problem in the above code by giving "another_base" an explicit copy constructor:

struct another_base 
{
  int x;

  another_base(another_base const& b) : x(b.x) {}

  another_base(int y) : x(y) {}
};

Starting to conclude that this is a compiler bug unless someone can tell me why this is legitimate.

More information:

struct derived;

struct base
{
  base() {}

private:
  base(derived const&);
};

struct base2 
{
  base2() {}
  //base2 (base2 const&) {}
};

struct derived : base, base2 {};

int main()
{
  derived d1; derived d2(d1);
}

Looking more at Schaub's answer I took the above code and compiled it. It compiles just fine until you uncomment base2's copy constructor declaration. Then it will blow up in the way I'm assuming was expected with the original code (no access to private constructor in base). So templates aren't even part of the issue; you can recreate the problem without them. Looks like it's an MI issue, which VS has always been a little slow at getting right.

I've changed the tags to reflect this finding.

Posted to MS's bug repository

http://connect.microsoft.com/VisualStudio/feedback/details/587787/implicit-copy-constructor-calls-base-with-derived-type-under-specific-conditions

I included a work around in the example code.

解决方案

I'm pretty sure the answer to your question is "never".

Section 12.8.2 of the ANSI C++ Standard says

A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments.

Section 12.8.3 says

A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv-qualified) X and either there are no other parameters or else all other parameters have default arguments. A member function template is never instantiated to perform the copy of a class object to an object of its class type. [Example:

struct S { 
    template <typename T> S(T);
};

S f();

void g() {
    S a( f() ); // does not instantiate member template
}

-- end example]

这篇关于MI和隐式复制构造函数的错误(是:在什么条件下,模板可以是复制构造函数?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆