此问题基于的代码适用于我在GCC-4.6上运行,但不适用于另一个使用CLang-3.0的用户,都在C++ 0x模式下运行。
template <typename T>
struct MyBase
{
//protected:
T m;
template <typename Args...>
MyBase( Args&& ...x ) : m( std::forward<Args>(x)... ) {}
};
MyBase
对象可以接受构造函数参数的任何列表,只要T
支持该构造签名即可。问题与特殊成员函数有关。T
是默认可构造的)。 MyBase
将获得一个自动定义的复制构造函数(只要T
是可复制的),它将引导T
复制构造。 因此,如果我将
MyBase<T> const &
作为唯一的构造函数参数传递,则调用哪个构造函数,转发一个还是隐式复制一个?typedef std::vector<Int> int_vector;
typedef MyBase<int_vector> VB_type;
int_vector a{ 1, 3, 5 };
VB_type b{ a };
VB_type c{ b }; // which constructor gets called
我用户的问题是将其用作基类。编译器提示说,他的类无法合成自动定义的拷贝构造函数,因为它找不到与基类的构造函数模板匹配的对象。它不应该为自己的自动复制构造函数调用
MyBase
自动复制构造函数吗? CLang是否因提出冲突而错误? 最佳答案
我只是和Richard Corden在一起,我们之间的结论是,问题与可变参数或右值无关。在这种情况下,隐式生成的拷贝构造将MyBase const&
作为参数。模板化的构造函数将参数类型推导为MyBase&
。尽管它不是拷贝构造函数,但这是一个更好的匹配。
我用于测试的示例代码如下:
#include <utility>
#include <vector>i
template <typename T>
struct MyBase
{
template <typename... S> MyBase(S&&... args):
m(std::forward<S>(args)...)
{
}
T m;
};
struct Derived: MyBase<std::vector<int> >
{
};
int main()
{
std::vector<int> vec(3, 1);
MyBase<std::vector<int> > const fv1{ vec };
MyBase<std::vector<int> > fv2{ fv1 };
MyBase<std::vector<int> > fv3{ fv2 }; // ERROR!
Derived d0;
Derived d1(d0);
}
我需要删除对初始化程序列表的使用,因为clang尚不支持此方法。除了
fv3
的初始化失败之外,该示例均会编译:为MyBase<T>
合成的拷贝构造函数采用MyBase<T> const&
,因此传递fv2
调用可变参数构造函数,将对象转发给基类。我可能误解了这个问题,但是基于
d0
和d1
,似乎默认构造函数和拷贝构造函数都是综合的。但是,这是最新版本的gcc和clang。也就是说,它没有解释为什么没有合成拷贝构造函数,因为有一个合成的拷贝构造函数。为了强调此问题与可变参数列表或右值无关:以下代码显示了调用模板化构造函数的问题,尽管看起来好像调用了拷贝构造函数,而拷贝构造函数从来都不是模板。这实际上是某种令人惊讶的行为,我绝对没有意识到:
#include <iostream>
struct MyBase
{
MyBase() {}
template <typename T> MyBase(T&) { std::cout << "template\n"; }
};
int main()
{
MyBase f0;
MyBase f1(const_cast<MyBase const&>(f0));
MyBase f2(f0);
}
结果,将问题中的可变参数构造函数添加到没有任何其他构造函数的类中,将改变行为复制构造函数的工作方式!我个人认为这很不幸。这实际上意味着类
MyBase
也需要使用copy和move构造函数进行扩充: MyBase(MyBase const&) = default;
MyBase(MyBase&) = default;
MyBase(MyBase&&) = default;
不幸的是,这似乎不适用于gcc:它提示默认的拷贝构造函数(它声称不能在类定义中定义带有非const引用的默认拷贝构造函数)。 Clang接受此代码,没有任何投诉。使用采用非const引用的复制构造函数的定义可同时用于gcc和clang:
template <typename T> MyBase<T>::MyBase(MyBase<T>&) = default;
关于c++ - 复制构造函数和转发构造函数之间的冲突,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9287250/