Внутри алгоритма я хочу создать лямбду, которая принимает элемент по ссылке на const:
template<typename Iterator>
void solve_world_hunger(Iterator it)
{
auto lambda = [](const decltype(*it)& x){
auto y = x; // this should work
x = x; // this should fail
};
}
Компилятору не нравится этот код:
Ошибка: »const« -qualifier не может быть применен к »int&«(Перевод вручную с немецкого)
Тогда я понял, что decltype(*it)
это уже ссылка, и, конечно, это не может быть сделано const
, Если я удалю const
код компилируется, но я хочу x = x
терпеть неудачу.
Давайте на минуту поверим программисту (это я) и избавимся от const
и явный &
, который удаляется из-за правил свертывания ссылок, в любом случае. Но подождите, это decltype(*it)
на самом деле гарантированный быть ссылкой, или я должен добавить явное &
быть в безопасности?
Если мы не доверяем программисту, я могу придумать два решения для решения проблемы:
(const typename std::remove_reference<decltype(*it)>::type& x)
(const typename std::iterator_traits<Iterator>::value_type& x)
Вы можете решить для себя, какой из них более уродливым. В идеале я хотел бы получить решение, которое не включает в себя никакого шаблонного метапрограммирования, потому что моя целевая аудитория никогда не слышала об этом раньше. Так:
Вопрос 1: есть decltype(*it)&
всегда такой же как decltype(*it)
?
Вопрос 2: Как я могу передать элемент по ссылке на const без шаблонного метапрограммирования?
Вопрос 1: нет, требование к InputIterator просто *it
может быть преобразовано в T (таблица 72 в разделе «Требования к итераторам»).
Так decltype(*it)
может быть, например, const char&
для итератора которого value_type
является int
, Или это может быть int
, Или же double
,
С помощью iterator_traits
не эквивалентно использованию decltype
решить, какой вы хотите.
По той же причине, auto value = *it;
делает не обязательно даст вам переменную с типом значения итератора.
Вопрос 2: может зависеть от того, что вы подразумеваете под шаблонным метапрограммированием.
Если для типа признаков используется TMP, то нет способа указать «постоянную ссылку на тип значения итератора» без TMP, поскольку iterator_traits
является единственным средством доступа к типу значения произвольного итератора.
Если вы хотите, чтобы decltype
тогда как насчет этого?
template<typename Iterator>
void solve_world_hunger(Iterator it)
{
const auto ret_type = *it;
auto lambda = [](decltype(ret_type)& x){
auto y = x; // this should work
x = x; // this should fail
};
}
Возможно, вам придется захватить ret_type
чтобы использовать его тип, я не могу легко проверить в данный момент.
К сожалению, это разыменовывает итератор дополнительное время. Возможно, вы могли бы написать какой-нибудь умный код, чтобы избежать этого, но умный код оказался бы альтернативной версией remove_reference
следовательно, ТМП.
Других решений пока нет …