C ++:部分专门化模板的类型参数作为另一个模板类的成员类型

时间:2016-07-29 06:24:59

标签: c++ templates partial-specialization

我有一个模板struct SFoo,它包含一个成员结构SZug

template <typename tTYPE>
struct SFoo
  {
    struct SZug {};
  };

我有另一个带有类型参数的结构SBar

template <typename tTYPE>
struct SBar
  { /* stuff */ };

我想使用SBar专门化SZug作为类型参数,如下所示:

template <typename tTYPE>
struct SBar<typename SFoo<tTYPE>::SZug>
  { /* different stuff */ };

这不会编译 - LLVM输出:

  

不可扣除的模板参数&#39; tTYPE&#39;

虽然编译器可以很容易地推断它,如果它希望,我猜测它只是C ++规范需要专门涵盖这种情况。

有没有办法实现这个目标?
(注意:我目前正在努力将SZug移到SFoo之外并使用using声明,但这很丑陋。)

2 个答案:

答案 0 :(得分:2)

我不确定我是否完全理解您要执行的操作,但您可以尝试以下操作(只需要向SZug添加特定属性:

template <typename tTYPE>
struct SFoo {
    struct SZug {
        // Add this to be able to obtain SFoo<T> from SFoo<T>::SZug
        using type = tTYPE;
    };
};

然后是一个小模板,用于检查类型是否为SFoo<T>::SZug

template <typename tTYPE, typename Enabler = void>
struct is_SZug: public std::false_type { };

template <typename tTYPE>
struct is_SZug<tTYPE, typename std::enable_if<
  std::is_same<tTYPE, typename SFoo<typename tTYPE::type>::SZug>{}
>::type>: public std::true_type { };

如果类型为SBar,则对SZug模板进行略微修改以启用“特化”:

template <typename tTYPE, typename Enabler = void>
struct SBar
  { static void g(); };

template <typename tTYPE>
struct SBar<tTYPE, typename std::enable_if<is_SZug<tTYPE>{}>::type>
  { static void f(); };

一点检查:

void f () {
  SBar<int>::g();
  SBar<SFoo<int>::SZug>::f();
}

注意:您也可以直接将SFoo<T>设置为type中的SFoo<T>::SZug属性,您只需要更改{{1}的第二个参数一点点。

答案 1 :(得分:1)

您可以通过以下方式获取效果(打印出0 1,BTW):

#include <type_traits>
#include <iostream>

namespace detail
{   
    struct SZugBase{};
}   

template <typename tTYPE>
struct SFoo                                                                                                                                
{   
    struct SZug : public detail::SZugBase {}; 
};  

template<typename tType, bool IsFoo>
struct SBarBase
{   
    int value = 0;
};  

template<typename tType>
struct SBarBase<tType, true>
{   
    int value = 1;
};  

template <typename tTYPE>
struct SBar : public SBarBase<tTYPE, std::is_convertible<tTYPE, detail::SZugBase>::value>
{ /* stuff */ };

int main()
{   
    SBar<int> b0; 
    SBar<SFoo<int>::SZug> b1; 

    std::cout << b0.value << " " << b1.value << std::endl;
}   

<强>解释

首先,我们给SZug一个普通类基础:

namespace detail
{   
    struct SZugBase{};
}   

template <typename tTYPE>
struct SFoo                                               
{   
    struct SZug : public detail::SZugBase {}; 
};  

请注意以下事项:

  1. SZugBase未被任何内容参数化,因此很容易独立于SFoo

  2. 的参数引用它
  3. SZugBase位于detail命名空间中,因此,通过常见的C ++约定,您可以告诉客户您的代码忽略它。

  4. 现在我们给SBar两个基类,专门研究某些东西是否可以转换为SZug的非模板库:

    template<typename tType, bool IsFoo>
    struct SBarBase
    {   
        int value = 0;
    };  
    
    template<typename tType>
    struct SBarBase<tType, true>
    {   
        int value = 1;
    };  
    

    最后,我们只需要使SBar成为这些基础的子类(取决于专业化):

    template <typename tTYPE>
    struct SBar : public SBarBase<tTYPE, std::is_convertible<tTYPE, detail::SZugBase>::value>
    { /* stuff */ };
    

    请注意,您不必在此处专注SBar,而是专门研究基类。但这有效地产生了相同的效果。