【问题标题】:typedef X<T>=T::UserType1, but if not applicable, typedef X<T>=UserType2typedef X<T>=T::UserType1,但如果不适用,typedef X<T>=UserType2
【发布时间】:2019-04-15 01:31:00
【问题描述】:

这里是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&lt; Param1 ,SlotCustom ,DefaultType&gt;,这意味着如下伪代码:-

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

怎么做?

Here 是一个类似的问题。
主要区别在于X&lt;T&gt;只能有一个bool,而且很多东西都是硬编码的。

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

【问题讨论】:

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


    【解决方案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

    您最初尝试的问题是,在decltype() 的表达式中调用check 函数需要一些参数来进行重载解析,以便SFINAE 魔法可以发生。我上面的示例依赖std::declval 来引入必要类型的虚拟参数。另外,请注意,我的辅助函数使用引用而不是直接按值传递类型。这样它也适用于不可复制的类型。请注意,如果Slot&lt;T&gt;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&lt;T&gt; 是有效类型时才会选择特化。请注意,上述解决方案需要 C++17。如果您必须停留在 C++14 中(鉴于您自己的示例依赖于 C++17,您可能不需要),例如,您可以提供自己的 void_t 实现(如 here 所解释的那样) ):

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

    【讨论】:

    • 你从哪里学到这些东西(书、网站等)?在学习一些重要的模板专业化(例如,从那个 cppreference SFINAE 链接)时,我总是很头疼。
    • @javaLover 我还添加了一个基于您现在使用函数重载的初始方法的版本;展示你是如何做到这一点的……
    • @javaLover 我无法为您提供我从中学到这些东西的具体来源……这只是您多年来积累的经验……而且已经太多年了……而且我我还在学习…… ;-) 你可能想在这里查看列表:stackoverflow.com/questions/388242/…Modern C++ Design 绝对是值得推荐的读物,尽管现在有点过时了。我还推荐 C++ 编程语言 来进行该语言的基本完整之旅(目前认为还不是完全最新的)......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-07
    • 1970-01-01
    • 2020-09-30
    • 2012-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多