Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a simpler way to get to a member of a class wrapped in a smart pointer?

Tags:

c++

c++11

Apologies for the cryptic title. Suppose this definition:

struct TestNode {
    using CostType = double;
};

I would like to be able to define a class template like this:

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

In the above definition, NodeP can be either a simple or a smart pointer to a class that defines CostType, such as TestNode. The problem: how can one specify a default value for the MyPolicy template parameter to be the CostType of the node type corresponding to NodeP?

Here is my solution so far:

// 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 {
};

Is there a simpler approach to this problem? In particular, am I missing a standard library facility that could make the solution simpler?

like image 412
AlwaysLearning Avatar asked Oct 29 '15 12:10

AlwaysLearning


People also ask

Does C ++ 11 have smart pointers?

Introduction of Smart PointersC++11 comes up with its own mechanism that's Smart Pointer. When the object is destroyed it frees the memory as well. So, we don't need to delete it as Smart Pointer does will handle it. A Smart Pointer is a wrapper class over a pointer with an operator like * and -> overloaded.

How do you use a smart pointer?

A smart pointer is like a regular (typed) pointer, like "char*", except when the pointer itself goes out of scope then what it points to is deleted as well. You can use it like you would a regular pointer, by using "->", but not if you need an actual pointer to the data. For that, you can use "&*ptr".

What is unique_ptr?

std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.

In what kind of circumstances would you use a raw pointer instead of a smart pointer?

The rule would be this - if you know that an entity must take a certain kind of ownership of the object, always use smart pointers - the one that gives you the kind of ownership you need. If there is no notion of ownership, never use smart pointers.


2 Answers

There is a helper class in the standard library called pointer_traits. It looks like it's exactly what you want.

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;
}
like image 187
Андрей Беньковский Avatar answered Nov 08 '22 07:11

Андрей Беньковский


With some usings I may be a little more readable

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;

Now in your code

template <typename NodeP,
          typename MyPolicy = cost_type_t<NodeP>>
struct TT {
};
like image 25
Guillaume Racicot Avatar answered Nov 08 '22 08:11

Guillaume Racicot