0

Here is MCVE (uncompilable) :-

#include <iostream>
#include <type_traits>
//-- library ---
template<class T,template<class>class Slot,class DefaultType> 
  class GetType{
    template <typename C> static Slot<T> check( Slot<T>*);
    template <typename> static DefaultType check(...);
    public: using type=decltype(check<T>());
}; 
template<class T,template<class>class Slot,class DefaultType>
  using X = typename GetType<T,Slot,DefaultType>::type; 

Here is its usage :-

//--- user defined ---
class B {public: using MyType=int;};
class C{};
template<class T> using SlotCustom = typename T::MyType;
int main(){
    using ShouldInt=X< B ,SlotCustom ,long>; //B::Mytype =int     , result:int
    using ShouldLong=X< C ,SlotCustom ,long>;//C::Mytype not exist, result:long
    std::cout<< std::is_same_v<ShouldInt, int> <<std::cout; //should true
    std::cout<< std::is_same_v<ShouldLong, long> <<std::cout; //should true
}

My objective is to create a library typedef X< Param1 ,SlotCustom ,DefaultType> that means as the following pseudo code:-

if ( SlotCustom<Param1> has meaning) return "SlotCustom<Param1>" ;
else return "DefaultType"; //i.e. by default 

How to do it?

Here is a similar question.
The main difference is that X<T> there can be only a bool, and many things are hardcoded.

I am new to template specialization. The solution might be obvious, but I can't find it.

javaLover
  • 6,347
  • 2
  • 22
  • 67

1 Answers1

1

If I understand your question correctly, then your approach can be made to work, for example

template <template <class> class Slot, class DefaultType>
struct GetType
{
    template <typename T>
    static Slot<T>&& deduce(T&&);
    static DefaultType&& deduce(...);

    template <typename T>
    using type = std::remove_reference_t<decltype(deduce(std::declval<T>()))>;
};

template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<Slot, DefaultType>::template type<T>;

live demo here

The problem with your initial attempt was that the call to your check function in the expression for decltype() needed some argument for overload resolution to take place so that the SFINAE magic can happen. My example above relies on std::declval to introduce a dummy argument of the necessary type. Also, note that my helper functions use references rather than passing the types by value directly. This is so that it also works with types that are not copyable. Note that there will be problems if Slot<T> or the DefaultType are reference types themselves. One would have to, e.g., introduce additional wrapper types to deal with that…

Alternatively, you could use partial class template specialization to pick the correct type, for example:

template <class T, template <class> class Slot, class DefaultType, typename = void>
struct GetType
{
    using type = DefaultType;
};

template <class T, template <class> class Slot, class DefaultType>
struct GetType<T, Slot, DefaultType, std::void_t<Slot<T>>>
{
    using type = Slot<T>;
};

template <class T, template <class> class Slot, class DefaultType>
using X = typename GetType<T, Slot, DefaultType>::type;

live demo here

The trick here lies in the use of the last template parameter with default argument void. Due to the way the matching of partial class template specializations works (see, e.g., this answer), the specialization will only be picked if Slot<T> is a valid type. Note that above solution requires C++17. If you have to stay within C++14 (which you probably don't, given that your own example relies on C++17), you can, e.g., provide your own implementation of void_t (as explained here):

template <typename... T> struct make_void { using type = void; };
template <typename... T> using void_t = typename make_void<T...>::type;
Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
  • Where did you learn these things (book,site,etc)? I always got headache while studying some non-trivial template specialization (e.g. from that cppreference SFINAE link). – javaLover Apr 15 '19 at 02:27
  • 1
    @javaLover I also added a version based on your initial approach using function overloading now; to show how you could have made that one work… – Michael Kenzel Apr 15 '19 at 02:49
  • 1
    @javaLover I wouldn't be able to give you specific sources where I learned these things from…it's just stuff you pick up over years of experience… And it's been far too many years…and I'm still learning… ;-) You may wanna check out the list here: https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list. *Modern C++ Design* is definitely a recommended read, albeit a bit dated by now. I would also recommend *The C++ Programming Language* for a basically complete tour of the language (thought also not completely up-to-date at this point)… – Michael Kenzel Apr 15 '19 at 02:58