10

I want to get a templatized way of finding if a type is a shared_ptr and based on that I want to have a new specialization of a function.

Example main function is,

template <class T> inline void CEREAL_LOAD_FUNCTION_NAME( RelaxedJSONInputArchive & ar, NameValuePair<T> & t ) { std::cout << " CEREAL_LOAD_FUNCTION_NAME NameValuePair 1 " << std::endl; ar.setNextName( t.name ); ar( t.value ); } 

If t.value is shared_ptr then I want to have a different function specialization. I have tried below,

template <class T> inline typename std::enable_if<is_pointer<T>::value, void>::type CEREAL_LOAD_FUNCTION_NAME( RelaxedJSONInputArchive & ar, NameValuePair<T> & t ) { std::cout << " CEREAL_LOAD_FUNCTION_NAME NameValuePair 2 " << std::endl; ar.setNextName( t.name ); ar( t.value ); } 

But it does not seem to work. These are part of c++11 cereal library. Which I am trying to customize.

3

3 Answers 3

18

the following may help:

template<typename T> struct is_shared_ptr : std::false_type {}; template<typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {}; 

then you can do the following to get the correct function:

template <class T> typename std::enable_if<is_shared_ptr<decltype(std::declval<T>().value)>::value, void>::type func( T t ) { std::cout << "shared ptr" << std::endl; } template <class T> typename std::enable_if<!is_shared_ptr<decltype(std::declval<T>().value)>::value, void>::type func( T t ) { std::cout << "non shared" << std::endl; } 

live demo

Sign up to request clarification or add additional context in comments.

2 Comments

Will it work in my case. Actually I have to get a new specialization of the function based on the type of a member called value. If T::value is shared_ptr then I need new specialization.
This looks like the correct answer for the question.
13

This is a basic case of template specialization. The following is a type trait that determines if a type T is a shared_ptr or not. It can be used the same way std::is_pointer, which you already use.

#include <memory> #include <type_traits> template<class T> struct is_shared_ptr : std::false_type {}; template<class T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {}; 

Demonstration :

static_assert(is_shared_ptr<std::shared_ptr<int>>::value == true, ""); static_assert(is_shared_ptr<int>::value == false, ""); 

6 Comments

I like the simplicity of this answer.
This definitely works and I also love the simplicity, but I don't understand why it works. Can anyone explain or point me to cpp reference or similar explaining this?
@IronAttorney The answer contains a link to en.cppreference.com/w/cpp/language/partial_specialization which explains what partial specialization is. It basically says "there is a class template call is_shared_ptr with 1 type argument" and then says "when the template argument is a type of std::shared_ptr<T> use this version of the template instead".
Yeah sorry, I didn't give much detail to what was confusing me. So that is the right area, but to me it reads like you'll end up with a specialisation of std::shared_ptr<std::shared_ptr<int>> as T is already a std::shared_ptr<int>. I'd have thought you'd need something more like template<template<class T> class OUTER_T, class T> struct is_shared_ptr<std::shared_ptr<T>> or something similar (sorry, I've forgotten exacly how you have to write such a thing now, but hopefully that's close enough to get my meaning)
That confusion aside, you have helped me properly get what is happening here. The partial specialisation has a base class of std::true_type. That's cleared the fog alot there, thanks!
|
4

If the type provided is itself a std::shared_ptr of some unknown type T, then the following use of SFINAE should help! Since all smart pointers provide a member type "element_type" we can specialize for std::shared_ptr<T>, std::weak_ptr<T>, and std::unique_ptr<T> as follows:

template<typename T, typename Enable = void> struct is_smart_pointer { enum { value = false }; }; template<typename T> struct is_smart_pointer<T, typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, std::shared_ptr<typename T::element_type>>::value>::type> { enum { value = true }; }; template<typename T> struct is_smart_pointer<T, typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, std::unique_ptr<typename T::element_type>>::value>::type> { enum { value = true }; }; template<typename T> struct is_smart_pointer<T, typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, std::weak_ptr<typename T::element_type>>::value>::type> { enum { value = true }; }; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.