typedef X <t> = T :: UserType1,但如果不适用,则typedef X <t> = UserType2

时间:2019-04-15 01:31:01

标签: c++ templates c++14 typedef template-specialization

这里是MCVE(无法编译):-

#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; 

这是它的用法:-

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

我的目标是创建一个库 typedef X< Param1 ,SlotCustom ,DefaultType>,该库的含义如下:-

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

该怎么做?

Here是一个类似的问题。
主要区别在于X<T>只能是布尔值,并且许多东西都是硬编码的。

我是模板专门知识的新手。解决方案可能很明显,但我找不到。

1 个答案:

答案 0 :(得分:1)

例如,如果我正确理解了您的问题,那么您的方法就可以奏效

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

您最初尝试时遇到的问题是,在check表达式中调用decltype()函数需要一些参数来进行重载解析,以便发生SFINAE魔术。我上面的示例依靠std::declval引入了必需类型的伪参数。另外,请注意,我的辅助函数使用引用,而不是直接通过值传递类型。这样一来,它也适用于不可复制的类型。请注意,如果Slot<T>DefaultType本身是引用类型,则会出现问题。例如,必须引入其他包装类型来解决这一问题……

或者,您可以使用部分类模板专门化来选择正确的类型,例如:

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

这里的窍门在于使用最后一个模板参数和默认参数void。由于部分类模板专业化的匹配工作的方式(例如,参见this answer),只有在Slot<T>是有效类型的情况下才选择专业化。请注意,以上解决方案需要C ++ 17。如果您必须停留在C ++ 14之内(鉴于您自己的示例依赖于C ++ 17,那么您可能不必这么做),例如,可以提供自己的void_t实现(如{ {3}}):

template <typename... T> struct make_void { using type = void; };
template <typename... T> using void_t = typename make_void<T...>::type;