根据 c-tor 的特定条件选择要初始化的变量?

Choose which variable to initialize based on certain condition at c-tor?

就像我有这个结构:

struct S
{
   S(const S &arg) : (arg.bIsDouble ? v1{arg.v1} : v{arg.v}) {}

   bool bIsDouble{false};   

   union {
      vector<int> v;

      double v1;
   };
} ;

如何让复制构造函数根据某些条件初始化 'v' 或 'v1'?

我会把你的工作外包给 Boost.Variant:

struct S {
    S(const S&) = default;
    boost::variant<double, std::vector<int> > v;
};

如果您不想使用 Boost,可以阅读有关如何编写可区分联合 here,然后实现您自己的联合的信息。

因为你只需要两种类型,所以这并不太复杂,尽管它仍然很容易出错并且涉及很多代码:

struct DoubleOrVector {
    bool is_double;
    static constexpr std::size_t alignment_value = std::max(alignof(double), alignof(std::vector));

    alignas(alignment_value) char storage[std::max(sizeof(double), sizeof(std::vector))];

    DoubleOrVector(double v)
        : is_double(true)
    {
        new (storage) double(v);
    }

    // similar for vector

    DoubleOrVector(const DoubleOrVector& dov) 
        : is_double(dov.is_double)
    {
        if (is_double) {
            new (storage) double(dov.asDouble());
        }
        else {
            new (storage) std::vector<int>(dov.asVector());
        }
    }

    double& asDouble() { 
        assert(is_double);
        return *reinterpret_cast<double*>(storage);
    }

    std::vector<int>& asVector() { 
        assert(!is_double);
        return *reinterpret_cast<std::vector<int>*>(storage);
    }

    // plus other functions here
    // remember to explicitly call ~vector() when we need to
};

然后我们仍然默认复制构造函数:

struct S {
    S(const S&) = default;
    DoubleOrVector v;
};

构造函数初始化列表在这里无济于事。

您必须在 class 构造函数中使用 placement new,然后在析构函数中销毁(通过手动调用析构函数)正确的成员。另外,既然你定义了析构函数,你应该定义或删除五巨头的其余部分。

最小代码:

struct S
{
    bool bIsDouble{false};

    union {
        vector<int> v;
        double v1;
    };

    S(bool d) : bIsDouble(d)
    {
        if(!bIsDouble)
            new(&v) vector<int>();
        // no need to create or destroy a double, since it is trivial
    }

    ~S()
    {
        if(!bIsDouble)
            v.~vector<int>();
    }

    // the other Big Five members are implicitly deleted
    // so no copying, unless you write it yourself.
};

请注意,类型之间的切换比较困难:如果您使用了 vector,现在想使用 double,您需要先销毁 vector。我建议将数据隐藏在访问函数后面以强制执行不变性。

...或者只使用 boost::variant。它更简单,更不容易出错。