基于L或R值模板的成员变量类型

时间:2014-10-10 01:26:41

标签: c++ templates

我试图根据l或r值是否传递给函数来存储引用成员变量或移动构造值成员变量。这是我尝试过的。是否有关于如何获得我想要的功能的指导?

尝试1

template <class T>
struct ARR
{
    ARR(T o) : obj(std::forward(o)) {}

    typename std::conditional<std::is_lvalue_reference<T>::value, std::decay<T>::type &, std::decay<T>::type>::type obj;
};

template <class T>
void make_ARR(T && o)
{
    ARR<decltype(o)> t(std::forward(o));
}

尝试2

template <class T>
struct ARR
{
};

template <class T>
struct ARR <T &&>
{
    ARR(T o) : obj(std::move(o)) {}
    typename std::decay<T>::type obj;
};

template <class T>
struct ARR <T &>
{
    ARR(T o) : obj(o) {}
    typename std::decay<T>::type & obj;
};

template <class T>
void make_ARR(T && o)
{
    ARR<decltype(o)> t(std::forward(o));
}

2 个答案:

答案 0 :(得分:1)

在调试器中检查以下内容的最终结果似乎表明这是您正在寻找的内容,即使该类的语义可能与您所追求的完全不同。

template<bool> class val_or_ref;

template<>
class val_or_ref<false> {

public:

    template<typename T>
    struct ARR {

    public:
        T obj;

        ARR(T &&value) : obj(std::move(value)) {}
    };

    template<typename T>
    static ARR<T> make(T &&t)
    {
        return ARR<T>(std::forward<T>(t));
    }
};

template<>
class val_or_ref<true> {

public:

    template<typename T>
    struct ARR {

    public:
        T &obj;

        ARR(T &value) : obj(value) {}
    };

    template<typename T>
    static ARR<T> make(T &t)
    {
        return ARR<T>(t);
    }
};

template<typename T>
auto make_ARR(T &&t)
    -> decltype(val_or_ref<std::is_lvalue_reference<T>::value>
            ::make(std::forward<T>(t)))
{
    return val_or_ref<std::is_lvalue_reference<T>::value>
        ::make(std::forward<T>(t));
}

通过以上结果,结果如下:

int n=4;

auto a=make_ARR(7);
auto b=make_ARR(n);

gdb告诉我:

(gdb) p a
$1 = {obj = 7}
(gdb) p b
$2 = {obj = @0x7fffffffe384}
(gdb) p &a
$3 = (val_or_ref<false>::ARR<int> *) 0x7fffffffe380
(gdb) p &b
$4 = (val_or_ref<true>::ARR<int> *) 0x7fffffffe370
(gdb) p b.obj
$5 = (int &) @0x7fffffffe384: 4

可能还有其他更紧凑的方法,但这似乎是不言自明的。

答案 1 :(得分:1)

感谢Sam,我从他的代码中退后一步,得到了一个工作紧凑的解决方案。感谢您的帮助,我现在可以看到原始尝试中的所有问题。

首先,我注意到ARR的两个定义是在ref_or_val类中定义的。我想把它们拿出来摆脱ref_or_val类。接下来,我将我的前锋与Sam的比较,并注意到我错过了模板。最后,返回值都是复制构造的,所以我将输入返回给构造函数以节省一些开销。

最终守则

template<typename T>
struct val_ARR
{
    T obj;
    val_ARR(T && value) : obj(std::move(value)) {}
};

template<typename T>
struct ref_ARR
{
    const T & obj;
    ref_ARR(const T & value) : obj(value) {}
};

template<typename T>
auto make_ARR(T && t) -> typename std::conditional<std::is_lvalue_reference<decltype(t)>::value, ref_ARR<T>, val_ARR<T>>::type
{
    return std::forward<T>(t);
}

中级代码

这是Sam的代码和我的最终代码之间的步骤。我从中学到了很多东西,特别是当从模板开始进行小的更改然后编译以确保事情仍然有效时。

template<typename T>
struct val_ARR
{
    T obj;
    val_ARR(T &&value) : obj(std::move(value)) {}
};

template<typename T>
struct ref_ARR
{
    const T &obj;
    ref_ARR(const T &value) : obj(value) {}
};

template<bool> class val_or_ref;

template<>
struct val_or_ref<false> 
{
    template<typename T>
    static val_ARR<T> make(T &&t)
    {
        return std::forward<T>(t);
    }
};

template<>
struct val_or_ref<true> 
{
    template<typename T>
    static ref_ARR<T> make(const T &t)
    {
        return t;
    }
};

template<typename T>
auto make_ARR(T &&t)  -> decltype(val_or_ref<std::is_lvalue_reference<T>::value>::make(std::forward<T>(t)))
{
    return std::forward<T>(t);
}