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

Типы С++, которые невозможно назвать

При чтении страницы Wikipedia в объявлении мне было интересно узнать,

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

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

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

4b9b3361

Ответ 1

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

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 являются индивидуально выраженными, но более общий класс типов более высокого уровня.

EDIT: и для ответа на ваш ответ на другой ответ этот пример невыразим в С++ 03. У вас не может быть шаблона функции, который будет обертывать любую функцию T1 foo(T2) и соответствовать как аргументу, так и возвращаемому типу обернутой функции.

Ответ 2

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

Ответ 3

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

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

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

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

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

С С++ 98/TR1 часто не следует указывать типы, зависящие от параметров шаблона. Черты предоставляют нам так много информации, но в конечном итоге decltype является гораздо более чистым решением многих проблем. Много информации, доступной вам, когда метапрограммирование доступно только потому, что библиотеки, такие как boost или loki, используют несколько трюков, скрытых в темных углах языка С++ 98.

Конечно, это не имеет отношения к вашему вопросу, но я считаю, что стоит упомянуть, что компиляторы С++ 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());
}