Прозрачные операторные функторы
Visual Studio 2013 Preview поддерживает функцию C++14, которая называется (согласно этой странице) "Прозрачные операторные функторы". Мне не ясно, что это значит. Ближайшее предложение C++14, которое я нашел, это, но я не уверен, что это то же самое: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3421
Я ищу более четкое объяснение того, что это такое, почему это улучшение, и, возможно, фрагмент, демонстрирующий его использование.
1 ответ
Предложение о прозрачных операторных функторах существует как способ иметь обобщенные функторы, расположенные в <functional>
, Я лично считаю, что само предложение имеет очень хороший пример, который поможет проиллюстрировать необходимость в нем. Однако я пойду дальше и попытаюсь это объяснить.
Предположим, у вас есть функция, очень простая функция:
template<typename T, typename U>
auto less_than(T&& t, U&& u) -> decltype(std::forward<T>(t) < std::forward<U>(u)) {
return std::forward<T>(t) < std::forward<U>(u);
}
Однако вы хотите использовать эту обобщенную функцию в <algorithm>
заголовок. У вас есть два варианта, чтобы сделать его структурным функтором:
struct MyLessThanFunctor {
template<typename T, typename U>
auto operator()(T&& t, U&& u) -> decltype(std::forward<T>(t) < std::forward<U>(u)){
return std::forward<T>(t) < std::forward<U>(u);
}
};
Или в C++14, чтобы сделать полиморфную лямбду:
[](auto&& t, auto&& u) -> decltype(auto) {
return std::forward<decltype(t)>(t) < std::forward<decltype(u)>(u);
}
Оба очень многословны при использовании в алгоритме, например, так:
int main() {
std::vector<int> v = {112,12,1281271,1919101,29181,412,1 };
std::sort(std::begin(v), std::end(v), MyLessThanFunctor()); // one
std::sort(std::begin(v), std::end(v), [](auto&& t, auto&& u) -> decltype(auto) {
return std::forward<decltype(t)>(t) < std::forward<decltype(u)>(u);
});
}
Это предложение направлено на то, чтобы сделать его более компактным и обобщенным, сделав вместо этого следующее:
std::sort(std::begin(v), std::end(v), std::less<>());
Это дает вам идеальную пересылку и решает проблемы с усечением или проблемы, возникающие из-за смены контейнера, но не базового типа, назначенного контейнером, как указано в документе.
Предположим, у вас есть не обобщенный функтор:
struct Functor {
bool operator()(uint32_t a, uint32_t b) {
return a < b;
}
};
И вы используете это с вашим std::vector<uint32_t>
и все работает нормально, но вы забываете, что ваш функтор не обобщается, и используете его со своими std::vector<uint64_t>
, Вы видите проблему, которая возникла? Элементы будут усечены перед сравнением, что, вероятно, не то, что хотел пользователь. Обобщенные функторы решают эту проблему до того, как они возникнут.