Тип распада - что это такое и почему оно там?

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


Если вам интересно, почему я спрашиваю, ниже приведен мой рассказ о распаде типа всхлипа (ноне предмет вопроса):

Недавно я боролся с простыми шаблонами и хотел сделать что-то вроде этого:

template <class FunObj>
double DoStuff(FunObj fob) // note that this returns double, not FunObj, as e.g. std::for_each() does
{ /* ... */ }

struct MyFunObj {
    mutable size_t num_invoked; // collect usage statistics

    MyFunObj()
        :num_invoked(0)
    {}

    bool operator ()(double some_arg) const
    {
        ++ num_invoked;
        return sin(some_arg) < .5;
    }
};

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

MyFunObj fob;
DoStuff(fob); // passed by value, usage statistics are lost (no surprise here)

MyFunObj &ref = fob;
DoStuff(ref); // MyFunObj& decays to MyFunObj, usage statistics are lost

DoStuff(static_cast<MyFunObj&>(fob)); // again, hampered by type decay

Я знаю, как решить эту проблему, поэтому, пожалуйста, не отвечайте, как. Меня интересует только распад типа как таковой, и это здесь только в качестве мотивации моего вопроса / иллюстративного примера. Если хотите, можете опубликовать ненависть за мое использование mutable,

1 ответ

Решение

Я не думаю, что ваш вопрос показывает пример распада типа. Термин "распад" обычно используется для обозначения стандартных преобразований функция-указатель, массив-указатель и lvalue-to-rvalue. Что вас поражает, так это правила вывода аргументов шаблона.

Дело в том, что вывод аргументов шаблона основан на типах, а не на категориях значений. Тип ref в вашем примере это MyFunObjи это lvalue этого типа (Кстати, то же самое верно для fob). Так как вычет работает на типах, FunObj выводится на тип refчто действительно MyFunObj,

До C++11 не было способа вывести ссылочный тип. C++11 изменил это с помощью "пересылки ссылок". Они представили особый случай, когда передача lvalue типа U к параметру функции, объявленной как T&& (где T параметр шаблона шаблона функции) использует U& как тип для вычета вместо U, Но это особое правило, исключение. Обычно категории значений не играют роли в выводе типов.

Другие вопросы по тегам