std :: function const правильность

11

Предположим, у меня есть вызываемый тип, например:

struct mutable_callable
{
    int my_mutable = 0;
    int operator()() { // Not const
        return my_mutable++;
    }
};

Обратите внимание, что mutable_callableесть неконстантный, operator()который изменяет переменную-член .....

Теперь предположим, что я создал std::functionиз моего типа:

std::function<int()> foo = mutable_callable{};

Теперь я могу сделать это:

void invoke(std::function<int()> const& z)
{
    z();
}

int main()
{
    invoke(foo); // foo changed.....oops
}

Теперь, насколько я могу сказать , std::functionS operator()является constв соответствии с : https://en.cppreference.com/w/cpp/utility/functional/function/operator ()

Так что мое внутреннее ощущение, что вы не должны быть в состоянии сделать это .....

Но потом посмотрим: https://en.cppreference.com/w/cpp/utility/functional/function/function

Кажется, это не накладывает никаких ограничений на то, имеет ли вызываемый тип константу operator()......

Итак, мой вопрос заключается в следующем: я правильно предположил, что std::function<int()> const&это, по сути, одно и то же, как std::function<int()>&то, что на самом деле нет разницы между поведением двух ... и если это так, то почему это не constправильно?

DarthRubik
источник
@MaxLanghof Нет ..... std::functionимеет эквивалент struct a{ std::any x; };в нем .....
DarthRubik
Вот небольшой фрагмент внутренней части std::functionреализации MSVC : i.stack.imgur.com/eNenN.png где using _Ptrt = _Func_base<_Ret, _Types...>. Я считаю так.
Макс

Ответы:

3

Это сводится к тому же , как struct A { int* x; };, где в const A a;вы можете изменить значение из *(a.x)(но не там , где он указывает). Существует уровень косвенности std::function(от стирания типа), через который constне распространяется.

И нет, std::function<int()> const& fэто не бессмысленно. В a std::function<int()>& fвы сможете назначить другой функтор f, который вы не можете сделать в этом constслучае.

Макс Лангоф
источник
Ага ..... это действительно имеет большой смысл ..... все еще смущает на первый взгляд, хотя
DarthRubik
Я считаю, что это недостаток дизайна. Эта косвенность должна быть деталью реализации, прозрачной для пользователя, и константность может распространяться с использованием некоторого метапрограммирования.
Игорь Р.
@IgorR. Да, константность может распространяться. std::vectorделает это, std::unique_ptrне делает. Я чувствую, std::functionчто на самом деле речь не идет о выражении инвариантов состояния функтора. Может быть, мы могли бы повторно использовать отвратительные типы функций (т.е. std::function<int() const>), чтобы различать?
Макс
unique_ptrне должен распространять константу, как это делает обычный указатель. И std::function<int() const>не будет компилироваться.
Игорь Р.
@IgorR. Я знаю. Я хотел сказать, что некоторые части стандартной библиотеки делают это, а некоторые нет. К какой категории std::functionследует относиться, мне не ясно. И это std::function<int() const>было гипотетически - конечно, он не компилируется сейчас, но будет ли он удовлетворять, например, OP здесь, если это можно сделать допустимым, выражая «можно назначать только функторы с operator() const(или без состояния)»? (даже если за кулисами это было бы довольно жестоко из-за использования отвратительных типов функций)?
Макс