3

假设我有这样的事情:

class A
{
public:
    A(int x, int y)
    {
        std::cout << "Constructed from parameters" << std::endl;
    }

    // Non-copyable, non-movable
    A(A const&) = delete;
    A(A&&) = delete;
    A& operator=(A const&) = delete;
    A& operator=(A&&) = delete;
};
    
class B
{
public:
    B() = default;

private:
    A a{1,2};
};
    
int main()
{
    B b;
    return 0;
}

a这工作正常,通过调用构造函数使用默认值进行初始化A,然后打印Constructed from parameters.


然后,假设我想以a不同的方式初始化,所以我添加了一个构造函数,它接受一个初始化列表并更改我的代码:

class A
{
public:
    A(int x, int y)
    {
        std::cout << "Constructed from parameters" << std::endl;
    }
        
    A(std::initializer_list<int> someList)
    {
        std::cout << "Constructed from an initializer list" << std::endl;
    }

    // Non-copyable, non-movable
    A(A const&) = delete;
    A(A&&) = delete;
    A& operator=(A const&) = delete;
    A& operator=(A&&) = delete;
};
    
class B
{
public:
    B() = default;

private:
    A a{1,2,3};
};
    
int main()
{
    B b;
    return 0;
}

一切仍然按我的意愿工作,代码a通过调用A的第二个构造函数使用默认值初始化并打印Constructed from an initializer list


现在,假设我想保持原样,但通过第一个构造函数A返回设置的默认值。a如果A是可移动的,我可以使用A a = A(1,2);,但这里不是这种情况,那么我该怎么做呢?使用该构造函数设置默认值是不可能的吗?

编辑:我正在寻找适用于 C++14 的解决方案,但如果在 C++17 或 C++20 中有更好的解决方案,那也是我想知道的。

4

2 回答 2

4

如果 A 是可移动的,我可以使用A a = A(1,2);,但这里不是这样

好吧,对于 C++17 及更高版本,您可以在此处使用A a = A(1,2);,只要您将其作为声明/初始化!以下作品(在您的第二个代码片段中):

class B {
public:
    B() = default;
private:
    A a = A( 1, 2 ); // No assignment here - just an initialization.
};

并调用“从参数构造”。这是因为这里没有实际的赋值操作,只是一个初始化。但是,由于您所说的原因,以下操作会失败:

class B {
public:
    B() { a = A( 1, 2 ); } // error C2280: 'A &A::operator =(A &&)': attempting to reference a deleted function
private:
    A a{ 1,2,3 };
};

编辑:C++ 17 之前,以下是一种解决方法,在默认构造函数的初始值设定项列表中使用“老式”圆括号,而不是花括号B(在 clang-cl 中使用 C++14 进行测试)和 MSVC):

class B {
public:
    B() : a(1,2) {} // Using a{1,2} calls the "initializer list" constructor, however!
private:
    A a;
};
于 2020-10-22T11:38:41.937 回答
0

我认为如果没有某种“黑客”,这在 C++14 中是不可能的。一种这样的技巧是使用额外的消歧参数。例如:

class From_params {};

class A {
public:
    A(int, int, From_params = {})      // (1)
    {}
    
    A(std::initializer_list<int>)      // (2)
    {}

    ...
};

class B {
public:
    B() = default;

private:
    A a{1, 2, From_params{}};  // calls (1)
};
于 2020-10-22T14:27:56.737 回答