返回类型的要求可能有一些成员函数 SFINAE 在函数的翻译单元中消失了吗?
Requirements on returned type that may have some member functions SFINAE'd away in the function's translation unit?
精炼自Why is the destructor implicitly called?
我对调用约定的理解是函数在调用者要求的地方(或在约定的地方?)构造它们的结果。考虑到这一点,这让我感到惊讶:
#include <memory>
struct X; // Incomplete type.
// Placement-new a null unique_ptr in-place:
void constructAt(std::unique_ptr<X>* ptr) { new (&ptr) std::unique_ptr<X>{nullptr}; }
// Return a null unique_ptr:
std::unique_ptr<X> foo() { return std::unique_ptr<X>{nullptr}; }
https://godbolt.org/z/rqb1fKq3x
而 constructAt
编译,愉快地放置-new
ing 空值 unique_ptr<X>
,foo()
不编译,因为编译器想要实例化 unique_ptr<X>::~unique_ptr()
。我明白为什么它不能实例化那个析构函数(因为就语言而言,它需要遵循 d'tor 的非 nullptr
分支,然后删除内存 [https://Whosebug. com/questions/28521950/why-does-unique-ptrtunique-ptr-need-the-definition-of-t])。基本上没有完整的 X
,unique_ptr
的析构函数就被 SFINAE 去掉了(对吧?)。但是为什么返回值的函数必须知道如何销毁该值呢?调用者不是必须销毁它的人吗?
很明显,我的 constructAt
和 foo
功能在道德上并不等同。这种语言是迂腐的,还是有一些代码路径(例外?)其中 foo()
必须破坏该值?
在您的特定情况下,无法调用析构函数。但是,该标准以更一般的术语指定了析构函数 可能被调用 的情况。如果析构函数 可能被调用 它需要一个定义(即使没有可以调用它的路径)因此这将导致隐式实例化,这在您的情况下失败,因为 std::unique_ptr<X>
析构函数需要 X
才能完成。
特别是,对于 return
语句中的每个结果对象,析构函数 可能被调用 。
我认为这个选择的原因在CWG issue 2176中有描述:通常函数中可能有局部变量和临时变量,它们在return
语句的结果对象被销毁后被销毁建。但是如果销毁其中一个对象抛出异常,那么已经构造好的结果对象也应该被销毁。这需要定义析构函数。
CWG issue 2426 然后使析构函数可能被调用,即使由于上述推理没有实际调用,与实现一致。我认为做出这个选择只是因为它不需要编译器方面的任何额外决策并且已经实现了。
精炼自Why is the destructor implicitly called?
我对调用约定的理解是函数在调用者要求的地方(或在约定的地方?)构造它们的结果。考虑到这一点,这让我感到惊讶:
#include <memory>
struct X; // Incomplete type.
// Placement-new a null unique_ptr in-place:
void constructAt(std::unique_ptr<X>* ptr) { new (&ptr) std::unique_ptr<X>{nullptr}; }
// Return a null unique_ptr:
std::unique_ptr<X> foo() { return std::unique_ptr<X>{nullptr}; }
https://godbolt.org/z/rqb1fKq3x
而 constructAt
编译,愉快地放置-new
ing 空值 unique_ptr<X>
,foo()
不编译,因为编译器想要实例化 unique_ptr<X>::~unique_ptr()
。我明白为什么它不能实例化那个析构函数(因为就语言而言,它需要遵循 d'tor 的非 nullptr
分支,然后删除内存 [https://Whosebug. com/questions/28521950/why-does-unique-ptrtunique-ptr-need-the-definition-of-t])。基本上没有完整的 X
,unique_ptr
的析构函数就被 SFINAE 去掉了(对吧?)。但是为什么返回值的函数必须知道如何销毁该值呢?调用者不是必须销毁它的人吗?
很明显,我的 constructAt
和 foo
功能在道德上并不等同。这种语言是迂腐的,还是有一些代码路径(例外?)其中 foo()
必须破坏该值?
在您的特定情况下,无法调用析构函数。但是,该标准以更一般的术语指定了析构函数 可能被调用 的情况。如果析构函数 可能被调用 它需要一个定义(即使没有可以调用它的路径)因此这将导致隐式实例化,这在您的情况下失败,因为 std::unique_ptr<X>
析构函数需要 X
才能完成。
特别是,对于 return
语句中的每个结果对象,析构函数 可能被调用 。
我认为这个选择的原因在CWG issue 2176中有描述:通常函数中可能有局部变量和临时变量,它们在return
语句的结果对象被销毁后被销毁建。但是如果销毁其中一个对象抛出异常,那么已经构造好的结果对象也应该被销毁。这需要定义析构函数。
CWG issue 2426 然后使析构函数可能被调用,即使由于上述推理没有实际调用,与实现一致。我认为做出这个选择只是因为它不需要编译器方面的任何额外决策并且已经实现了。