聚合初始化具有不同的参数顺序

时间:2019-03-24 11:02:37

标签: c++ c++17

有什么方法可以指定与声明顺序不同的参数?

例如,假设我具有以下结构:

struct Coord
    {
        int x, y;
    };

我可以将其初始化为

auto a = Coord{ y(5),x(4) };

请注意,出于好奇我是在问这个问题,我真的不需要这样做。但是我想知道是否可以在不声明构造函数但指定参数的情况下初始化结构。

2 个答案:

答案 0 :(得分:6)

不幸的是,您不能更改结构成员构造的顺序。使用C ++ 20,您可以按名称指定成员(请参见designated initializers)。不幸的是,初始化的名称必须与成员的顺序相同。

这是cppreference(上面的链接)中的引号:

  

注意:乱序的指定初始化,嵌套的指定初始化,指定的初始化程序和常规初始化程序的混合以及数组的指定初始化在C编程语言中均受支持,但在C ++中是不允许的。

struct Coord
{
    int x, y;
};

初始化:

auto a = Coord{ .x=4, .y = 5}; // Ok with C++20

但是这不起作用(请参见上面的引用):

auto a = Coord{ .y=5, .x = 4}; // ERROR

对于其他顺序,您必须定义一个构造函数或一个辅助函数。

compiler explorer尝试一下。

答案 1 :(得分:2)

我不确定您要实现的目标,但是,您似乎想防止X和Y交换,甚至在发生时自动更新正确的成员。

Jonathan Boccara的博客文章很不错:https://www.fluentcpp.com/2016/12/08/strong-types-for-strong-interfaces/

想法是你写:

 using X = NamedType<int, struct XTag>;
 using Y = NamedType<int, struct YTag>;

struct Coord
    {
    X x;
    Y y;
    };

 auto a = Coord{ X(4),Y(5) };

如果所有内容都是默认可构造的,并且结构中的类型是唯一的,则可以使用可变参数模板来为正确的成员分配正确的值。

构造函数将类似于:

struct Coord
    {
    template<typename ...T>
    Coord(T &&...t)
        {
        assignByType(std::forward_as_tuple(x, y), std::forward<T>(t)...);
        }

    X x{0};
    Y y{0};
    };

根据类型,您可以分配值,甚至可以断言所有类型都在其中,并且所有类型都不会被忽略。

assignByType的实现可以是:

#include <utility>
#include <tuple>

template<typename ... T, typename ... U, typename V>
auto assignByTypeHelper(std::tuple<T &...> t, V &&v, U && ... u)
    {
    std::get<V &>(t) = std::forward<V>(v);
    if constexpr( sizeof...(U))
        {
        assignByTypeHelper(std::move(t), std::forward<U>(u)...);
        }
    }

template<typename ... T, typename ... U>
auto assignByType(std::tuple<T &...> t, U && ... u)
    {
    static_assert(sizeof...(T) == sizeof...(U));
    return assignByTypeHelper(std::move(t), std::forward<U>(u)...);
    }

位于compiler explorer的完整代码