C++ c++;使用嵌套对象优化将U放置回原处

C++ c++;使用嵌套对象优化将U放置回原处,c++,optimization,c++14,C++,Optimization,C++14,我有点困惑于安置的行为。 让我们看看 struct innerObject { innerObject(int ); }; class outterObject { innerObject member; public: outterObject(innerObject member); }; int main() { std::vector<outterObject> v1; v1.emplace_back(5); } struct-i

我有点困惑于安置的行为。 让我们看看

struct innerObject
{
    innerObject(int );
};

class outterObject
{
    innerObject member;
public:
    outterObject(innerObject member);
};

int main()
{
    std::vector<outterObject> v1;
    v1.emplace_back(5);
}
struct-innerObject
{
内部对象(int);
};
类outterObject
{
内部对象成员;
公众:
outterObject(innerObject成员);
};
int main()
{
std::向量v1;
v1.向后安放(5);
}
所以在这种情况下,我们可以传递整数,它可以工作


如果
innerObject
需要两个
int
s来构造,而不是只需要一个,那么构造函数呢?无论是
v1.emplace\u back(5,5)
还是
v1.emplace\u back({5,5})
还是我尝试的任何其他组合都不起作用。这有可能吗?有没有更好的选择来制造这样的东西?(优化)

您只需构建内部对象,然后将其放回:

v1.emplace_back(innerObject{10, 20});
或者,您可以为
outerObject
添加一个构造函数,该构造函数接受两个参数,然后调用
innerObject
构造函数。在这种情况下,您可以这样称呼它:

v1.emplace_back(10, 20);

避免任何类型复制/移动的唯一方法是外部类型通过提供一个通用构造函数来选择该类型的操作:

template <typename A0, typename... Args,
    std::enable_if_t<
        !std::is_same_v<std::decay_t<A0>, outterObject> &&
        std::is_constructible_v<outterObject, A0, Args...>
        , int> = 0>
outterObject(A0&& a0, Args&&... args)
    : member(std::forward<A0>(a0), std::forward<Args>(args)...)
{ }
  v1.emplace_back(5); // v1 is a vector of outerObject.
template=0>
outterObject(A0&&A0,Args&&…Args)
:成员(标准::转发(a0),标准::转发(args)…)
{ }
如果
innerObject
可以从2
int
s构造,则可以编写
v1.emplace_back(10,20)


如果这看起来太过分了,你可以一直做
v1.push_back({{10,20}})
。请注意,
push_-back()
,与
emplace_-back()
不同,它不推断其参数类型-它只是
t常量&
t&
。这允许您使用
{}
s

它对一个参数有效的原因是innerObject类的单个int构造函数充当转换构造函数。换句话说,outterObject构造函数接受innerObject对象,并且由于转换构造函数规则,它将单个int参数转换为innerObject

未使用显式说明符和 它可以用单个参数调用(直到C++11)称为 转换构造函数

转换构造函数仅适用于单参数构造函数

如果在innerObject构造函数接受单个int之前编写explicit,您将看到它不会编译,因为“explicit”关键字不允许int参数自动创建innerObject以传递给outerObject构造函数:

template <typename A0, typename... Args,
    std::enable_if_t<
        !std::is_same_v<std::decay_t<A0>, outterObject> &&
        std::is_constructible_v<outterObject, A0, Args...>
        , int> = 0>
outterObject(A0&& a0, Args&&... args)
    : member(std::forward<A0>(a0), std::forward<Args>(args)...)
{ }
  v1.emplace_back(5); // v1 is a vector of outerObject.
这种方法有效的唯一原因是5参数通过其非显式构造函数(取int)转换为innerObject。这种转换构造函数行为仅适用于单参数构造函数

如果需要,可以将双参数构造函数添加到innerObject:

innerObject(int x, int y)
    {
        std::cout << "constructor innerObject" << std::endl;
    }

谢谢,那么考虑一下什么是最好的选择:1)
v1.push_back({{10,20}})2)innerMember
<代码>v1.安放回(内部成员)3)内部成员<代码>v1.向后放置(标准::移动(内部成员))?我看到的是推回是这里最糟糕的选择。使用std::move时,我们使用的move构造函数(而不是copy)比不使用要多得多。所以我将使用v1.emplace_back(std::move(innerMember))因为移动通常更便宜。为了避免丑陋的
启用if\u t
我建议使用基于标记的方法,在C++17中使用类似于
的方法来消除复制构造函数和成员初始化构造函数之间的歧义。@JesperJuhl您的评论不正确。我第一次屈服于它,并进行了编辑,但我很匆忙,没有正确地思考。我回过头来回答。我使用
innerObject
explicit构造函数的版本在语义上等同于原始OP的示例,只有一个整数参数。在这两种方式中,您首先使用int参数调用
内部
构造函数,然后调用外部构造函数(从内部移动)。