Подтвердить что ты не робот

Когда следует использовать decltype (x) вместо auto, чтобы объявить тип переменной?

Я вижу decltype(x), используемый внутри макросов, где x - это имя переменной, потому что тип объекта неизвестен внутри макросов.

Например:

decltype(x) y = expr;

Я мог бы просто использовать auto вместо decltype. Итак, каковы ситуации, когда decltype требуется для объявления типа переменной вместо auto?

4b9b3361

Ответ 1

Вы должны использовать его, когда требуемый тип y:

  • отличается (или потенциально отличается) от типа expr. Если бы это было то же самое, то auto было бы более кратким.
  • аналогично для auto & или других модификаций типа expr, которые может выражать auto.

и одно из следующего:

  • зависит от чего-то в окружающем коде (т.е. не всегда одного и того же типа) и трудно писать, используя черты типа или аналогичные. Это будет происходить в коде шаблона. Может существовать черта типа, которую вы можете использовать для получения требуемого типа из параметров шаблона, но опять же, возможно, не так, что использование decltype поможет вам определить его.
  • всегда одного и того же типа (или зависит от параметров шаблона таким образом, который легко выразить с использованием существующих типов признаков или аналогичных), но тип очень длинный для записи, и есть гораздо более короткое и четкое выражение, которое вы можете вместо этого используйте.

Так, например, замена std::iterator_traits<RandomAccessIterator>::value_type на decltype(*it) вполне может быть победой, хотя auto часто обрабатывает такие случаи.

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

Ответ 2

Если вы хотите, чтобы y всегда имел тип объявленного типа x.

Ответ 3

decltype становится удобным, когда вам нужно вернуть неизвестный тип, который оценивается во время компиляции:

template<class A, class B>
void MultiplyAB(A a, B b, decltype(a*b)& output)
{
    output = a * b;
}

Кроме того, если вам не нравится способ обработки вывода ссылкой, то вы также можете использовать поздний указанный тип возврата (а также использовать decltype):

template<class A, class B>
auto MultiplyAB(A a, B b) -> decltype(a*b)
{
    return a * b;
}

Все это и многое другое описывается Б. Страуступом в часто задаваемых вопросах С++.

Ответ 4

Всякий раз, когда ваш тип переменной не связан с оцениваемым выражением.

например:

struct Bar
{
    Bar(int) {} // implicitly constructable
}

struct Bar2
{
    Bar2(int) {} // implicitly constructable
}

struct Foo
{
    static Bar var;
}

struct Foo2
{
    static Bar2 var;
}

template <typename T>
void dummy()
{
    decltype(T::var) myVar = 42;
}

dummy<Foo>(); // myVar is of type Bar1
dummy<Foo2>(); // myVar is of type Bar2
auto myAutoVar = 42; // type is int

Конечно, это всего лишь один случай использования, там еще много.

Ответ 5

decltype значительно более универсален, чем auto и всегда может использоваться вместо него. Поэтому я считаю довольно уверенным, что decltype должен использоваться только в тех случаях, когда он полностью необходим, поэтому, если auto создает неверный результат, вы должны использовать decltype. Также вы не можете использовать auto в качестве возвращаемых типов и параметров, поэтому вы можете использовать decltype там. С++ 14 значительно увеличит потенциальное использование auto, и я бы предположил, что С++ 17 пойдет дальше. Таким образом, ситуации с использованием decltype будут только тогда, когда вам нужно изменить результирующий тип expr

Еще одна вещь, которую следует учитывать, заключается в том, что decltype на самом деле не требуется, если вы не пишете код библиотеки, автоматически подходит для повседневного программирования, если вы хотите сделать свой код более кратким, это для обсуждения, используя как можно больше auto, насколько это возможно, это хорошо, но это практически необходимо при работе с невыразимыми типами, такими как lambdas.

Ответ 6

В контексте вашего вопроса

  • Вы должны использовать decltype, если в качестве исходной переменной требуется новая переменная с точно таким же типом.

  • Вы должны использовать auto, если хотите назначить значение некоторого выражения для новой переменной, и вы хотите, чтобы его тип был выведен.

decltype(x) y всегда объявляет y точно таким же типом, с которого был объявлен тип x. В частности:

  • Если x имеет тип const int, то y будет иметь тип const int.
  • Если x имеет тип int[100], то y будет иметь тип int[100].
  • Если x имеет тип int f(int), то y будет иметь тип int f(int). Да, это фактически объявляет другую функцию с тем же типом, что и оригинал.
  • Если x имеет тип int&, то y будет иметь тип int&; и если x имеет тип int&&, то y будет иметь тип int&&.

auto y = x объявит y со следующими типами, когда x имеет следующие типы:

  • Если x имеет тип const int, то y будет иметь тип int. То есть auto разделяет cv-квалификаторы верхнего уровня.
  • Если x имеет тип int[100], то y будет иметь тип int*. То есть auto выполняет преобразование указателя в. [1]
  • Если x имеет тип int f(int), то y будет иметь тип int (*)(int). То есть auto выполняет функцию преобразования указателя функции. [2]
  • Наконец, если x имеет тип int& или int&&, то y будет иметь тип int. То есть auto удаляет ссылки.

[1] Вы не можете использовать decltype здесь, потому что вы не можете копировать-инициализировать массив.

[2] Вы не можете использовать decltype здесь, потому что вы не можете инициализировать функцию.

[3] Причина, по которой ссылки auto разделяет ссылки, состоит в том, что С++ не имеет выражений ссылочного типа! После инициализации "ссылка" ссылки становится невидимой.

Обратите внимание, что decltype также делает что-то совершенно другое, когда его аргумент не является id-выражением, которое я не буду здесь вставлять.