Типы C ++, которые невозможно назвать - PullRequest
20 голосов
/ 06 марта 2011

Читая страницу Википедии о decltype , мне было любопытно высказывание

Его основное предназначение [decltype's] является общим программирование, где это часто трудно, или даже невозможно , назвать типы, которые зависят от шаблона параметры.

Хотя я могу понять часть сложности этого утверждения, каков пример, когда необходимо назвать тип, который нельзя назвать в C ++ 03?

РЕДАКТИРОВАТЬ : Моя точка зрения такова, что все в C ++ имеет объявление типов. С чего бы это случалось, когда невозможно назвать тип? Кроме того, разве классы черт не предназначены для получения информации о типах? Могут ли классы черт быть альтернативой decltype?

Ответы [ 3 ]

13 голосов
/ 06 марта 2011

На странице википедии, на которую вы ссылаетесь, прекрасный пример:

int& foo(int& i);
float foo(float& f);

template <class T> auto transparent_forwarder(T& t) −> decltype(foo(t)) {
  return foo(t);
}

Обратите внимание, что foo(int&) возвращает int& (ссылочный тип), в то время как foo(float&) возвращает float (тип без ссылки).Без decltype невозможно в шаблоне указать тип, который представляет «тип возврата функции foo, которая принимает аргумент t типа T».

В этом примереэто не конкретный конкретный конкретный тип, который невозможно выразить - либо int&, либо float могут быть выражены индивидуально, - это универсальный класс типов более высокого уровня.

РЕДАКТИРОВАТЬ: ичтобы ответить на ваш комментарий к другому ответу, этот пример невыразим в C ++ 03.У вас не может быть шаблона функции, который будет переносить любую функцию T1 foo(T2) и соответствовать как аргументу, так и возвращаемому типу упакованной функции.

11 голосов
/ 06 марта 2011

Существуют типы в C ++ 0x (и в C ++ 03, но реже), которые нельзя назвать явно, например, тип decltype(f) после объявления auto f = [](int x) -> int {return x;};. Вам нужно typedef, чтобы decltype привело к чему-либо, чтобы вообще получить имя. Классы признаков могут использоваться для определения возвращаемых типов, но они беспорядочные, и пользователь должен дублировать все свои перегрузки функций с перегрузками классов признаков; это трудно сделать правильно для таких случаев, как применение функций (посредством неявного преобразования указателей) ко всем подклассам данного базового класса.

1 голос
/ 06 марта 2011

Как вы указали, тип, если он существует, известен компилятору, иначе он не будет существовать. Однако, это не всегда легко или даже доступно программисту на C ++ 03.

N1607 упомянуть в своем заключении следующее:

В C ++ 2003 невозможно до выразить тип возврата функции шаблон во всех случаях . Более того, выражения, включающие призывы к шаблоны функций обычно имеют очень сложные типы, которые практически невозможно написать рука

Вопрос в том, как нам получить доступ к этому типу как к программисту. Это не всегда тривиальный процесс, часто неосуществимый. Это становится все более сложным, когда у вас есть выражение, для которого вы хотите знать тип результата. Вам придется разбить его на части, чтобы вычислить типы результатов. Невозможно упростить этот процесс с помощью шаблонов (во всяком случае, без оценки выражения). Нарушение выражения будет подвержено ошибкам, утомительным и кошмарным сном. Подумайте об этом коде:

x.g()[b.a(e)]->f();

В C ++ 98 / TR1 часто невозможно назвать типы, которые зависят от параметров шаблона. Traits предлагает нам так много информации, но в конечном итоге decltype является гораздо более чистым решением многих проблем. Большая часть информации доступна вам, когда метапрограммирование доступно только потому, что библиотеки, такие как boost или loki, используют несколько уловок, скрытых в темных углах языка C ++ 98.

Конечно, это не имеет отношения к вашему вопросу, но я считаю, что стоит упомянуть, что компиляторы C ++ 98 уже имеют механику, чтобы знать эти типы. Это именно то, что предлагает sizeof, за исключением того, что он возвращает вам размер. decltype повторно использует некоторые из этих функций и решает эти проблемы с большей элегантностью.

Что касается другого (академического) примера:

struct Foo
{
    struct
    {
        int x;
    } bar;
};

template<typename T>
void
f(const T& t)
{
    // C++03, How can I name the type of T::bar ?

    // C++0x
    // decltype(t.bar) cpy;
    // Do stuff with our local cpy
}

int
main()
{
    f(Foo());
}
...