是否有更简单的方法来获取包含在智能指针中的类的成员?

时间:2015-10-29 12:59:19

标签: c++ c++11

为神秘的标题道歉。假设这个定义:

struct TestNode {
    using CostType = double;
};

我希望能够像这样定义一个类模板:

template <typename NodeP,
          typename MyPolicy = /* CostType of the node type corresponding to NodeP */ >
struct TT {
};

在上面的定义中,NodeP可以是定义CostType的类的简单或智能指针,例如TestNode。问题:如何将MyPolicy模板参数的默认值指定为与CostType对应的节点类型的NodeP

到目前为止,这是我的解决方案:

// like std::remove_pointer, but works with smart pointers as well
template <typename PT> struct my_remove_pointer {
    using type = typename
        std::remove_reference< decltype( *((PT)nullptr) ) >::type;
};

struct TestNode {
    using CostType = double;
};

template <typename NodeP,
          typename MyPolicy = typename my_remove_pointer<NodeP>::type::CostType>
struct TT {
};

这个问题是否有更简单的方法?特别是,我错过了一个标准的库设施,可以使解决方案更简单吗?

3 个答案:

答案 0 :(得分:7)

标准库中有一个名为pointer_traits的辅助类。看起来它正是你想要的。

run online

#include <iostream>
#include <memory>
#include <typeinfo>

struct TestNode {
    using CostType = double;
};

template <typename NodeP,
          typename MyPolicy = typename std::pointer_traits<NodeP>::element_type::CostType>
struct TT {
    typedef MyPolicy xxx;
};

int main () {
    TT<TestNode*>::xxx a = 2.8;
    TT<std::unique_ptr<TestNode>>::xxx b = 3.14;
    std::cout << a << std::endl;
    std::cout << b << std::endl;
    return 0;
}

答案 1 :(得分:1)

通过一些使用,我可能会更具可读性

template<typename T>
using remove_pointer_t = typename my_remove_pointer<T>::type;

template<typename T>
using cost_type_t = typename remove_pointer_t<T>::CostType;

现在在你的代码中

template <typename NodeP,
          typename MyPolicy = cost_type_t<NodeP>>
struct TT {
};

答案 2 :(得分:0)

由于智能指针支持解除引用和.get(),我们可以使用void_t编写一个类型特征来获取基础类型:

template <typename... >
using void_t = void;

// base case: not any kind of pointer
template <typename T, typename = void>
struct underlying_type {
    using type = T;
};

// raw pointer
template <typename T, typename = void>
struct underlying_type<T*, void> {
    using type = T;
};

// smart pointer
template <typename T>
struct underlying_type<T, void_t<
                decltype(*std::declval<T>()),
                decltype(std::declval<T>().get())
                >>
{
    using type = std::remove_reference_t<
                     decltype(*std::declval<T>())
                 >;
};

template <typename T>
using underlying_type_t = typename underlying_type<T>::type;

如果需要支持非指针(我不确定),那么你可以这样做:

template <typename T>
using underlying_type_t = std::remove_reference_t<decltype(*std::declval<T>())>;

无论哪种方式,一旦你有了别名:

template <typename NodeP,
          typename MyPolicy = underlying_type_t<NodeP>::Cost>
struct TT { ... };