Любая разница между std:: forward <T> и std:: forward <decltype (t)>?

эти функции эквивалентны?

template <class T>
void foo(T && t)
{
    bar(std::forward<T>(t));
}

template <class T>
void foo2(T && t)
{
    bar(std::forward<decltype(t)>(t));
}

template <class T>
void foo3(T && t)
{
    bar(std::forward(t));
}

если они есть, могу ли я всегда использовать этот макрос для идеальной пересылки?

#define MY_FORWARD(var) std::forward<decltype(var)>(var)

или просто используйте

bar(std::forward(t));

Я считаю, что foo2 и foo3 такие же, но я обнаружил, что люди всегда используют forward, как foo, есть ли причина явно писать тип?

Я понимаю, что T и T&& - два разных типа, но я думаю, что std::forward<T> и std::forward<T&&> всегда дают тот же результат?


Edit:

причина, по которой я хочу использовать макрос, - это то, что я хочу сохранить некоторую типизацию в следующем коде С++ 1y, у меня есть много похожих кодов в разных местах

#define XLC_FORWARD_CAPTURE(var) var(std::forward<decltype(var)>(var))
#define XLC_MOVE_CAPTURE(var) var(std::move(var))

template <class T, class U>
auto foo(T && func, U && para )
{
    auto val = // some calculation
    return [XLC_FORWARD_CAPTURE(func),
            XLC_FORWARD_CAPTURE(para),
            XLC_MOVE_CAPTURE(val)](){
              // some code use val
              func(std::forward<U>(para)); 
          };
}

Ответы

Ответ 1

Являются ли эти функции двумя эквивалентными?

Да, они эквивалентны. decltype(t) совпадает с T&&, а в случае std::forward нет разницы между T и T&&, независимо от того, что T.

Могу ли я использовать этот макрос для идеальной пересылки?

Да, вы можете. Если вы хотите сделать свой код нечитаемым и неподъемным, сделайте это. Но я категорически против этого. С одной стороны, вы ничего не получаете от использования этого макроса. И, с другой стороны, другие разработчики должны взглянуть на определение, чтобы понять его, и это создает потенциал для тонких ошибок. Например, добавление дополнительных круглых скобок не будет работать:

MY_FORWARD((t))

Напротив, форма с decltype вполне допустима. В частности, это предпочтительный способ пересылки параметров из общих лямбда-выражений, поскольку нет явных параметров типа:

[](auto&& t) { foobar(std::forward<decltype(t)>(t)); }

Я проигнорировал третий вариант с std::forward(t), потому что он недействителен.


Обновление:. В отношении вашего примера: вместо call-by-reference для шаблона функции foo вы можете использовать call-by-value. Затем вы можете использовать std::move вместо std::forward. Это добавляет два дополнительных шага к коду, но никаких дополнительных операций копирования. С другой стороны, код становится намного чище:

template <class T, class U>
auto foo(T func, U para)
{
    auto val = // some calculation
    return [func=std::move(func),para=std::move(para),val=std::move(val)] {
        // some code use val
        func(std::move(para)); 
    };
}