29 Ocak 2018 Pazartesi

std::forward metodu

Giriş
std::forward'ın ne işe yaradığını uzun bir süre anlayamadım. Genellikle template kodlarında kullanılıyor. Daha sonra std::forward'ın static_cast<T&&> ile aynı şey olduğunu görünce herşey daha açık hale geldi. Metodun içi şöyle. Yani t parametresini r-vlue haline getiriyor.
template< class T >
T&& forward( typename std::remove_reference<T>::type& t );
Daha okunaklı hali şöyle
template <class T>
T&& forward(typename std::remove_reference<T>::type& t) noexcept
{
  return static_cast<T&&>(t);
}
Scott Meyers'in "Effective Modern C++" kitabındaki açıklaması şöyle
Item 23:Understand std::move and std::forward
...
The story for
std::forward is similar to that for std::move, but whereas std::move unconditionally casts its argument to an rvalue, std::forward does it only under certain conditions. std::forward is a conditional cast. It casts to an rvalue only if its argument was initialized with an rvalu.
...
Given that both std::move and std::forward boil down to casts, the only difference being that std::move always casts, while std::forward only sometimes does, you might ask whether we can dispense with std::move and just use std::forward everywhere. From a purely technical perspective, the answer is yes: std::forward  can do it all. std::move isn’t necessary. Of course, neither function is really necessary, because we could write casts everywhere, but I hope we agree that that would be, well, yucky.
...
std::move's attractions are convenience, reduced likelihood of error, and greater clarity...
Bu konuyu mükemmel açıklayan cevap burada.

std::forward() metodu Perfect Forwarding olarak tanımlı template metodlarda kullanılır.

std::forward her zaman T parametresi ile kullanılır.
Örnek
Şu kullanım şekli yanlıştır.
T&& param
std::forward(param)
Şöyle kullanmak gerekir.
std::forward<T>(param);
Örnek
Elimizde şöyle bir kod olsun. Bu kod derlenmez.
template<typename... Args>
Wrapper(Args&&... args) : x(std::make_unique<X>(std::forward(args)...)) {}
Şöyle yaparız. Sebebi ise derleyicinin args'a bakarak tipleri çıkaramaması.
std::forward<Args>(args)...
Örnek
Bazı kodlarda şöyle yapılıyor. Bir farkı var mı  bilmiyorum
std::forward<T&&>(param);
r-value method dispatch
std::forward method dispatching için kullanılabilir.
class OraclePreparedStatement
{
public:
  template<typename T>
  void bind_param(uint32_t col_index, T&& param)
  {
    bind_param_impl(col_index, std::forward(param), 
                    std::is_integral<std::remove_reference_t<T>>());
  }

private:
  template<typename T>
  void bind_param_impl(uint32_t col_index, T&& param, std::true_type)
  {
    statement->setNumber(col_index, oracle::occi::Number(param));
  }

  template<typename T>
  void bind_param_impl(uint32_t col_index, T&& param, std::false_type)
  {
    statement->setString(col_index, std::forward<T>(param));
  }

  OracleConnection::StatementWrapper statement;
};
Bu metodu haliyle şöyle çağırabiliyoruz.
OraclePreparedStatement stmt;
auto col_index = 1;
stmt.bind_param(col_index++, 15);
stmt.bind_param(col_index++, std::string("test string"));

Hiç yorum yok:

Yorum Gönder