Агрегированная инициализация с другим порядком аргументов - PullRequest
1 голос
/ 24 марта 2019

Есть ли способ указать аргументы в порядке, отличном от порядка объявления?

Например, допустим, у меня есть следующая структура:

struct Coord
    {
        int x, y;
    };

Могу ли я его инициализировать?as

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

Обратите внимание, что я спрашиваю это из любопытства, мне не нужно делать что-то подобное.Но я хочу знать, могу ли я инициализировать структуру без объявления конструктора, но с указанием аргументов.

Ответы [ 2 ]

6 голосов
/ 24 марта 2019

К сожалению, вы не можете изменить порядок построения членов структуры. В C ++ 20 вы можете указать членов по имени (см. обозначенные инициализаторы ). К сожалению, инициализированные имена должны быть в том же порядке, что и члены.

Вот цитата из 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

Для другого порядка вы должны определить конструктор или вспомогательную функцию.

Попробуйте в проводнике компилятора .

2 голосов
/ 24 марта 2019

Я не уверен, чего вы хотите достичь, однако похоже, что вы хотите предотвратить смену X и Y или даже автоматически обновить нужного участника, если это произойдет.

Джонатан Боккара имеет хороший пост в блоге об этом: 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)...);
    }

Полный код в Проводник компилятора

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...