我有一个复制和移动ctor删除的课程.
struct A
{
A(int a):data(a){}
~A(){ std::cout << "~A()" << this << " : " << data << std::endl; }
A(A const &obj) = delete;
A(A &&obj) = delete;
friend std::ostream & operator << ( std::ostream & out , A const & obj);
int data;
};
Run Code Online (Sandbox Code Playgroud)
我想用这个类的对象创建一个元组.但以下不编译:
auto p = std::tuple<A,A>(A{10},A{20});
Run Code Online (Sandbox Code Playgroud)
在另一方面,下面做编译,但给出了一个惊人的输出.
int main() {
auto q = std::tuple<A&&,A&&>(A{100},A{200});
std::cout << "q created\n";
}
Run Code Online (Sandbox Code Playgroud)
产量
~A()0x22fe10 : 100
~A()0x22fe30 : 200
q created
Run Code Online (Sandbox Code Playgroud)
这意味着一旦元组构造线结束,就会调用对象的dtor.那么,被毁物体元组的意义何在?
Bar*_*rry 11
这是不好的:
auto q = std::tuple<A&&,A&&>(A{100},A{200});
Run Code Online (Sandbox Code Playgroud)
你正在构造一个tuple对表达式末尾被破坏的临时对象的rvalue引用,所以你留下了悬空引用.
正确的陈述是:
std::tuple<A, A> q(100, 200);
Run Code Online (Sandbox Code Playgroud)
但是,直到最近,标准才支持上述内容.在N4296中,围绕相关构造函数的措辞tuple是[tuple.cnstr]:
Run Code Online (Sandbox Code Playgroud)template <class... UTypes> constexpr explicit tuple(UTypes&&... u);要求:
sizeof...(Types) == sizeof...(UTypes).is_constructible<Ti, Ui&&>::value对所有人都是如此i.
效果:使用相应的值初始化元组中的元素std::forward<UTypes>(u).
备注:此构造函数不应参与重载决策,除非每个类型都UTypes可以隐式转换为其对应的类型Types.
所以,这个构造函数没有参与重载解析,因为int它不能隐式转换为A.这已经通过改进pair并tuple解决了您的用例:
struct D { D(int); D(const D&) = delete; };
std::tuple<D> td(12); // Error
Run Code Online (Sandbox Code Playgroud)
这个构造函数的新措辞来自N4527:
备注:除非
sizeof...(Types) >= 1并且is_constructible<Ti, Ui&&>::value对所有人都适用,否则i此构造函数不应参与重载决策.构造函数是明确的,当且仅当is_convertible<Ui&&, Ti>::value是false至少一个我.
而且is_constructible<A, int&&>::value是真实的.
为了以另一种方式呈现差异,这里是一个非常简化的元组实现:
struct D { D(int ) {} D(const D& ) = delete; };
template <typename T>
struct Tuple {
Tuple(const T& t)
: T(t)
{ }
template <typename U,
#ifdef USE_OLD_RULES
typename = std::enable_if_t<std::is_convertible<U, T>::value>
#else
typename = std::enable_if_t<std::is_constructible<T, U&&>::value>
#endif
>
Tuple(U&& u)
: t(std::forward<U>(u))
{ }
T t;
};
int main()
{
Tuple<D> t(12);
}
Run Code Online (Sandbox Code Playgroud)
如果USE_OLD_RULES已定义,则第一个构造函数是唯一可行的构造函数,因此代码将无法编译,因为它D是不可复制的.否则,第二个构造函数是最可行的候选者,而且其中一个构造良好.
最近采用的是gcc 5.2和clang 3.6实际上都不会编译这个例子.所以你需要一个比这更新的编译器(gcc 6.0工作)或者想出一个不同的设计.
| 归档时间: |
|
| 查看次数: |
578 次 |
| 最近记录: |