Я хочу создать гибкую шаблонную функцию, которая может принимать как rvalue, так и lvalue. Вот как я это написал:
template<typename T>
decltype(auto) normalize_pose(T&& pose)
{
if (pose > 2 * M_PI) return std::forward<T>(pose - 2* M_PI);
}
Поэтому я дважды проверил функцию, и она кажется мне правильной. Тогда я решил проверить это и написал:
int a = 2;
auto test = factorgraph::normalize_pose(a);
Я получаю эту ошибку:
error: use of ‘decltype(auto) factorgraph::normalize_pose(T&&) [with T = int&]’ before deduction of ‘auto’
Если я пытаюсь добавить <int>
, я получаю сообщение об ошибке, что такой функции не существует.
Кстати, ваш пример странный, так как переадресация не нужна, здесь работает const ref.
@ Jarod42 Вы имеете в виду из-за правила вывода типа шаблона?
Вы не говорите, какую версию С++ вы компилируете. Использование умных выведенных типов возврата должно быть лучше, чем C++11
@UsingCpp Это ответ!!!! Он не смог вывести тип на моем примере, о боже, какой же я тупой...
@GemTaylor Да, тег добавлен
Я не могу воспроизвести это сообщение об ошибке.
@Brian Попробуйте с int a = 2
, код будет вне оператора if, и auto не сможет определить тип, я должен был добавить, какой int я использовал
Все равно не могу воспроизвести. Аргументы, передаваемые во время выполнения, не должны вызывать ошибки времени компиляции. См. coliru.stacked-crooked.com/a/b09f50dbccdb549f
Так должно быть
if (pose > 2 * M_PI) return std::forward<T>(pose) - 2* M_PI;
Применить std::forward
только к переменной.
И вам также нужно вернуть значение для ветки else (того же типа, чтобы удовлетворить
decltype(auto)
).
Но в вашем случае просто:
template<typename T>
auto normalize_pose(const T& pose)
{
return (pose > 2 * M_PI) ? pose - 2 * M_PI : pose;
}
справляется со всеми делами.
Да правильно, но я все еще получаю эту ошибку: error: use of ‘decltype(auto) factorgraph::normalize_pose(T&&) [with T = int&]’ before deduction of ‘auto’ auto test = factorgraph::normalize_pose(a);
Почти уверен, что decltype(auto)
также не нужен, поскольку std::forward<T>(pose) - 2* M_PI
, скорее всего, является выражением prvalue, а ветвь else - нет.
@NathanOliver Не знаю, ребята, я здесь, чтобы учиться, если это необходимо. Я просто следовал примеру из книги "Effective Modern C++"
Несвязанный: decltype(auto)
просто может быть T
. Я не знаю, почему ОП хочет этого!
Обновленный код завершается ошибкой, если передается целое число: coliru.stacked-crooked.com/a/13731e038276b632
Хотя это может быть спорным, поскольку нормализация int
не имеет большого смысла.
@UsingCpp Согласно книге, о которой я упоминал, это должен быть decltype, потому что автоматически отсекается часть & из-за правила вывода типа шаблона.
@NathanOliver, потому что это не всегда целое число, что, если я указал число с плавающей запятой?
Это все еще не работает из-за decltype(auto)
. Вы действительно хотите вернуть ссылку?
@NathanOliver Нет, но в некоторых случаях возврат ссылки будет важен.
@NathanOliver Думаю, на этом мои знания заканчиваются. Можете ли вы объяснить, что именно может пойти не так с этим кодом?
@НатанОливер: исправлено. Не хотел так сильно менять код OP. (вероятно, мы тоже можем избавиться от шаблона и просто использовать double
).
@Jarod42 Jarod42 Но что произойдет, если я укажу &int? Я предполагаю, что возвращаемое значение T будет int?
@Edmund Код в том виде, в каком он есть сейчас, действительно то, что вам нужно. Использование decltyp(auto)
для получения возвращаемой ссылки не может работать, потому что pose - 2 * M_PI
не будет иметь тот же тип, что и pose
. Чтобы decltype(auto)
работал, все пути управления должны возвращать один и тот же тип, и вы просто не можете этого сделать в этой ситуации.
@NathanOliver Вы имеете в виду, что если pose имеет значение int, тип возвращаемого значения будет двойным / плавающим?
@ Эдмунд Нет. Допустим, T
- это двойник. тогда pose - 2 * M_PI
будет типа double
. pose
, с другой стороны, будет иметь тип double const &
, поскольку это тип pose
. double
и double const &
не одного типа, поэтому decltype(auto)
не работает. Вы можете использовать решение Джарода, а затем, если вам нужно нормализованное значение, а также установить переменную на это нормализованное значение, вы можете использовать что-то вроде auto foo = (bar = normalize(bar)) * more_stuff;
@NathanOliver Просто быстрый вопрос, так почему же автор Effective Modern C++ пишет это как хороший пример? template<typename Container, typename Index> decltype(auto) authAndAccess(Container&& c, Index i) { authenticateUser(); return std::forward<Container>(c)[i]; }
@Edmund Потому что эта функция может возвращать только один тип. Это означает, что они могут возвращать точный ссылочный тип. Если бы функция была template<typename Container, typename Index> decltype(auto) authAndAccess(Container&& c, Index i) { if (authenticateUser()) return std::forward<Container>(c)[i]; else return foo; }
, то вы возвращаете 2 разных типа, и она не может работать.
@NathanOliver Хорошо, но если возвращаемый тип else был двойным (например, умноженным на M_PI), то мой пример кода будет действительным?
Давайте продолжить обсуждение в чате.
А как насчет ветки
else
? Что бы функция вернулаif (not)
?