Edw*_*nge 5 c++ multiple-inheritance
我很确定这个问题的答案是"从来没有,模板可以成为复制构造函数."
不幸的是,我花了3个小时搞清楚为什么我会收到关于递归的警告,跟踪它到复制构造函数,看着调试器发疯了,不让我看看递归代码,最后追踪到了一个缺失的'& '在基础构造函数中.
你看,我有这个复杂的基于策略的设计主机,现在已经工作了一段时间.我在一个中重写了两个策略,然后遇到了一个递归的复制构造函数.将其缩小为一个策略,该策略需要提供一个构造函数,该构造函数可以采用某种类型的XXX概念作为其参数,但在这种情况下,我只是丢弃它.所以我写了
struct my_policy
{
template < typename T >
my_polity(T const) {} // missing '&'...oops
};
Run Code Online (Sandbox Code Playgroud)
现在,my_policy是主机的基类(当然),这个小错误导致递归,其中主机的复制构造函数将链自身传递给这个模板化构造函数,而不是隐式的,编译器生成的复制构造函数.然后它当然会再次调用它的复制构造函数来创建临时的.
真正令人着迷的是我无法在简化代码中重新创建它.即使有一种模拟政策主持人的例子,我也无法实现.以下代码不会出现此问题:
#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;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用boost的参数库使"name"可以访问主机的7个左右参数.也许这就是问题,我不知道.无论如何,我想知道是否有人在那里知道具体条件(如果有的话)可能导致编译器合法地使用模板化构造函数将"base"作为复制构造函数或者从"derived"的隐式复制构造函数中使用.
编辑说明:
我通过给"another_base"一个显式的复制构造函数重新创建了上面代码中的问题:
struct another_base
{
int x;
another_base(another_base const& b) : x(b.x) {}
another_base(int y) : x(y) {}
};
Run Code Online (Sandbox Code Playgroud)
开始得出结论,这是一个编译器错误,除非有人能告诉我为什么这是合法的.
更多信息:
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);
}
Run Code Online (Sandbox Code Playgroud)
再看看Schaub的答案,我拿了上面的代码并编译了它.它编译得很好,直到您取消注释base2的复制构造函数声明.然后它会以我假设的原始代码(无法访问基础中的私有构造函数)的方式爆炸.所以模板甚至不是问题的一部分; 没有它们你可以重新创建问题.看起来这是一个MI问题,VS在做对时总是有点慢.
我已经更改了标签以反映这一发现.
发布到MS的bug存储库
我在示例代码中包含了一个解决方法.
使用Visual C++,导致复制构造函数参数的基本委派存在问题:
struct Derived;
struct Base {
Base(){ }
private:
Base(Derived const&);
};
struct Derived : Base { };
Derived d1;
Derived d2(d1);
Run Code Online (Sandbox Code Playgroud)
此代码有效,但Visual C++无法编译它,因为它们使用Derived对象调用基类复制构造函数.但是,标准要求编译器将Base const(或Base在某些情况下)传递给基类.
这是你的谜题的第一部分:模板是一个更好的匹配,因为复制构造函数需要派生到基本转换,但你的模板直接接受派生类,然后需要另一个副本,依此类推等等.请注意,模板不会在此处充当复制构造函数(给定VC++错误),就像上面的声明Base(Derived const&)没有声明复制构造函数一样.
第二部分是你的另一个问题的答案:标准是模棱两可的,在C++ 03中并不清楚实例化的模板是否可以作为复制构造函数.它说,在一张纸条中
因为模板构造函数永远不是复制构造函数,所以这种模板的存在不会抑制复制构造函数的隐式声明.模板构造函数与其他构造函数(包括复制构造函数)一起参与重载解析,并且如果模板构造函数提供比其他构造函数更好的匹配,则可以使用模板构造函数来复制对象.
它说,但下面有几段
从不实例化成员函数模板以将类对象的副本执行到其类类型的对象.
由于此文本出现的上下文(禁止按值参数复制构造函数),可能会认为这不是禁止从模板中按引用复制构造函数的实例化.但这种争论是没有实际意义的,面对这种模糊的措辞.
C++ 0x FCD清除了它,删除了奇怪的音符.现在很清楚,模板永远不会被实例化以执行副本,无论它是否会产生副引用或按值参数.但是如上所述,如果您碰巧使用VC++,并且它表现出这种行为,那么它与复制构造函数无关.
我很确定你的问题的答案是“从不”。
ANSI C++ 标准第 12.8.2 节说
类 X 的非模板构造函数是复制构造函数,如果其第一个参数的类型为 X&、const X&、易失性 X& 或 const 易失性 X&,并且没有其他参数或所有其他参数都有默认实参。
第 12.8.3 节说
如果类 X 的第一个参数的类型为(可选 cv 限定)X,并且没有其他参数或所有其他参数都有默认实参,则类 X 的构造函数的声明是格式错误的。成员函数模板永远不会实例化来执行类对象到其类类型的对象的复制。[例子:
struct S {
template <typename T> S(T);
};
S f();
void g() {
S a( f() ); // does not instantiate member template
}
Run Code Online (Sandbox Code Playgroud)
--结束示例]
| 归档时间: |
|
| 查看次数: |
572 次 |
| 最近记录: |