Является ли инициализация списка новой структуры {} с использованием специфичных для компилятора переменных?

Использование Visual Studio 2013 и компилятора C++ для написания еще одного связанного списка, и это произошло методом проб и ошибок. Это относится к Visual C++ или является частью стандарта?

Мне очень нравится этот синтаксис. Это очень чисто. Если вы написали библиотеку связанных списков, прежде чем вы знаете, что можете гоняться за указателями, пока ваш мозг не запутается. Однако этот синтаксис кристально ясен.

Много этого материала со статическими значениями инициализатора, но с использованием аргументов функций в качестве инициализаторов? Такого еще не видел.

Было бы приятно узнать, выдает ли компилятор GCC C/C++ ожидаемый результат. Кто угодно?

typedef struct link_in_list {
    struct link_in_list *next;
    int32_t key;
    int32_t value;
}   LINK, *pLINK;

// ----------------------------------------------------------------------------
pLINK prepend_list(pLINK head, int32_t key, int32_t value)
{
    if (NULL == head)   {
        // initialize with a constant, variable, and expression
        return new LINK{ NULL, key, (key * key) };
    }   else    {
        // initialize with stack variables
        return new LINK{ head, key, value };
    }
}

person Community    schedule 16.01.2015    source источник
comment
Это совершенно законно. Хотя это условие совершенно бессмысленно.   -  person T.C.    schedule 16.01.2015
comment
Совершенно бессмысленно.   -  person    schedule 16.01.2015
comment
@Т.С. Я изменил код, чтобы сделать инициализацию NULL более интересной, уничтожив ее идеальную бессмысленность.   -  person    schedule 23.01.2015


Ответы (1)


Это называется инициализацией списка и было введено в C++11. Это отличается от прямой инициализации множеством способов, на которые я хотел бы указать:

int x{3.5}; // illegal - narrowing
int x(3.5); // fine, x is 3, but does this make sense?

T fun(); // this is a function returning a T
T fun{}; // this is a default constructed object
         // of type T

 std::vector<int> v(10, 20); // 10 elems: 20, 20, 20, ..., 20
 std::vector<int> v{10, 20}; // 2 elems: 10, 20

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

Одним из дополнений к функциональности является то, что если T является «агрегатом» (то есть массивом или типом класса, который не имеет закрытых/защищенных членов, конструкторов, предоставляемых пользователем, базовых классов и виртуальных методов), то инициализация списка эквивалентна агрегатной инициализации.

То есть:

struct Foo {
    int a;
    char b;
    double c;
};

int i = 1;
char c = 'b';
double d = 42.;

Foo f{i, c, d};
Foo g = {i, c, d};

Эти строки эквивалентны.

person Barry    schedule 16.01.2015
comment
Хороший лаконичный конспект! - person Jonathan Leffler; 16.01.2015
comment
Как это относится к моему вопросу? Я не вижу никаких переменных, используемых в качестве инициализаторов. Моя структура {} - это POD, а не вектор. - person ; 16.01.2015
comment
Кроме того, заданные функции f и g, T foo(f(), g()); могут сначала оценить любой вызов; T foo{f(), g()}; оценит f() перед g(). Точно так же T foo(i++, i++); — это UB, а T foo{i++, i++}; — нет. - person T.C.; 16.01.2015
comment
@RocketRoy, почему часть переменных имеет значение? Я добавил объяснение инициализации списка, используемой в качестве агрегатной инициализации. - person Barry; 16.01.2015
comment
Вы заявляете здесь и сейчас, что это НЕ имеет значения? Это решит мой вопрос. Я прочитал 20 странных дискуссий по инициализации списка, включая ту, на которую вы ссылаетесь. В этих списках инициализации нет ни одной переменной, поэтому мой вопрос, является ли она специфичной для компилятора или частью стандарта. - person ; 16.01.2015
comment
@RocketRoy Вы действительно спрашиваете, можете ли вы инициализировать переменную с помощью переменной? Конечно. Так было всегда. Какой бесполезный язык не позволит вам сделать это? - person Barry; 16.01.2015
comment
@RocketRoy Примеры, как правило, используют литералы, поскольку вы знаете, что такое типы 1, 'b' и 42., и мне не нужно это говорить. Но я просто добавил переменные для вас. - person Barry; 16.01.2015
comment
Превосходно. Теперь, надеюсь, другие, кто тратит время на чтение сухих, бесполезных фолиантов, в Интернете или где-либо еще, об инициализации списка без переменной, которую можно найти где угодно, будут знать, что они также могут безопасно использовать этот синтаксис. Удивительно, как что-то настолько очевидное ускользнуло от десятков технических писателей. Мило с вашей стороны, что вы фактически ответили на заданный вопрос, даже если вы сочли необходимым сначала намекнуть, что я идиот. Должен любить StackOverflow. - person ; 16.01.2015
comment
Различие между константами, которые компилятор знает во время компиляции, и назначением переменных, известным только во время выполнения. Это важное различие. Классический C 89, например, не поддерживает объявление массива переменного размера, потому что компилятору необходимо знать требуемый размер стека во время компиляции, что невозможно с массивом размером во время выполнения [x]. Использование инициализации списка с переменными означает, что теперь есть новая краткая альтернатива использованию нескольких операторов присваивания, обычно состоящих из нескольких строк кода, после вызова new для выделения struct{}. - person ; 17.01.2015