Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get dereferenced type of template member for function return type

How can I get the correct type T for the following function to_vector?

template<typename K> struct A { K* p; size_t n; std::string foo; };
template<typename K> struct B { K* p; size_t n; float bar[3]; };

template<typename X>
std::vector<T> to_vector(const X& x) {   // what is T?
    return std::vector<T>(x.p, x.p+x.n); 
}

I tried with decltype(*std::declval<X>().p) but this results in error: forming pointer to reference type ‘float&’ for the following example:

A<float> a = { new float[10], 10, "hello" };
std::vector<float> v = to_vector(a);

This is part of some bigger code and there are more types like A and B. But all have a pointer p and a length n.

like image 784
Danvil Avatar asked Dec 28 '13 23:12

Danvil


2 Answers

You can probably use

typename std::decay<decltype(*X::p)>::type

for T because decltype is an unevaluated context and hence X::p is legal here. Also, std::decay seems like a good fit as it combines std::remove_reference with std::remove_cv.

like image 82
Daniel Frey Avatar answered Sep 26 '22 02:09

Daniel Frey


You are on the right track, you just need to use appropriate utility to get rid of the pointer/reference.

There is std::remove_reference, which you can use like:

typename std::remove_reference<decltype(*std::declval<X>().p)>::type

but it's a bit simpler to std::remove_pointer instead:

typename std::remove_pointer<decltype(std::declval<X>().p)>::type

(see, the * is gone, otherwise the same).

You might want to throw in std::remove_cv into the mix if the pointer might be cv-qualified, because vector elements shouldn't be.


As noted in the other, now deleted answer, you can write x.p instead of std::declval<X>().p if you use the trailing return type declaration:

template <typename X>
auto to_vector(const X& x) ->
    std::vector<typename std::remove_pointer<decltype(x.p)>::type>
like image 34
Jan Hudec Avatar answered Sep 24 '22 02:09

Jan Hudec