練習でstd::reference_wrapperがラップしてる型を取得するメタ関数を作ってみた


std::reference_wrapperの場合は保持してるTを返します。
std::reference_wrapperではない場合は受けた型をそのまま返します。

#include <functional>
#include <tuple>

namespace mpl {
template<class T>
struct remove_wrap;
{
    typedef T type;
};

template<class T>
struct remove_wrap<std::reference_wrapper<T>>
{
    typedef T type;
};
}   // namespace mpl
// "remove_ref.hpp"

こうなりました。


まぁとりあえずこれを無理やり使ってみます。

#include "remove_ref.hpp"
#include <type_traits>    // std::add_lvalue_reference

template <class T>
struct wrap2lvalue_ref
{
    typedef T type;
};

template <class T>
struct wrap2lvalue_ref<std::reference_wrapper<T>>
{
    typedef typename std::add_lvalue_reference<typename remove_wrap<T>::type>::type type;
};
}   // namespace mpl

#include <string>
#include <iostream>
#include <cxxabi.h>
using namespace mpl;

template <class... Args>
class Foo
{
    std::tuple<Args...> args_;
public:
    Foo(Args... args)
     : args_(args...)
    {
    }

    void operator()()
    {
        std::get<0>(args_) = "ABCDEF";
    }
};

template <class... Args>
Foo<typename wrap2lvalue_ref<Args>::type...> make_foo(Args... args)
{
    return Foo<typename wrap2lvalue_ref<Args>::type...>(args...);
}

int main(int argc, char** argv)
{
    std::string str("Hello World");
    std::cout << str << std::endl;
    auto f = make_foo(std::ref(str));
    f();                              // str = "ABCDEF"
    std::cout << str << std::endl;    // "ABCDEF"
}

std::reference_wrapperのデストラクタが呼ばれるコストを早々と避けたい時に使えるかも?


追記:map要らなかったmake_fooの時点でwrap2lvalue_refを適用すればよかったですね。

template <class... Args>
class Foo
{
    std::tuple<Args...> args_;
public:
    Foo(Args... args)
     : args_(args...)
    {
    }

    void operator()()
    {
        std::get<0>(args_) = "ABCDEF";
    }
};

template <class... Args>
Foo<typename wrap2lvalue_ref<Args>::type...> make_foo(Args... args)
{
    return Foo<typename wrap2lvalue_ref<Args>::type...>(args...);
}