简体   繁体   English

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

[英]C++: Partially specializing template's type parameter as another template class's member-type

I have a template struct SFoo that contains a member struct SZug : 我有一个模板结构SFoo ,其中包含成员struct SZug

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

I have another struct SBar that takes a type parameter: 我还有另一个带有类型参数的struct SBar

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

I would like to specialize SBar using SZug for the type parameter, like so: 我想专门SBar使用SZug的类型参数,如下所示:

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

This doesn't compile - LLVM outputs: 这不会编译-LLVM输出:

non-deducible template parameter 'tTYPE' 不可推导模板参数'tTYPE'

While a compiler could easily deduce this if it wished, I'm guessing it's just that the C++ spec would need to specifically cover this case. 尽管编译器可以根据需要轻松推断出这种情况,但我猜测这只是C ++规范需要专门涵盖这种情况。

Is there any way to achieve this? 有什么办法可以做到这一点?
(note: I'm currently working around it by moving SZug outside of SFoo and using a using declaration, but it's ugly.) (注:我目前工作围绕它通过移动SZug之外SFoo和使用using声明,但它是丑陋的。)

I am not sure I fully understood what you want to do, but you could try the following (it only requires adding a specific attributes to SZug : 我不确定我是否完全了解您想要做什么,但是您可以尝试以下操作(它只需要向SZug添加特定属性:

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

Then a small template to check if a type is a SFoo<T>::SZug : 然后是一个小模板,用于检查类型是否为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 { };

And a slight modification to the SBar template to enable the "specialization" if the type is a SZug : 如果类型是SZug ,则对SBar模板进行略微修改以启用“专业化”:

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(); };

A little check: 一点检查:

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

Note: You could also directly set SFoo<T> as the type attribute in SFoo<T>::SZug , you would simply need to change the second argument of std::is_same a little. 注意:您也可以直接将SFoo<T>设置为SFoo<T>::SZugtype属性,您只需要稍微更改std::is_same的第二个参数std::is_same

You can get the effect for which you're looking through the following (which prints out 0 1, BTW): 您可以通过以下方式获得想要的效果 (打印出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;
}   

Explanation 说明

First, we give SZug a regular-class base: 首先,我们为SZug提供常规课程:

namespace detail
{   
    struct SZugBase{};
}   

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

Note the following: 请注意以下几点:

  1. SZugBase is not parameterized by anything, so it is easy to refer to it independently of the parameter of SFoo SZugBase没有任何参数,因此很容易独立于SFoo的参数进行SFoo

  2. SZugBase is in a detail namespace, so, by common C++ conventions, you're telling clients of your code to ignore it. SZugBase位于detail名称空间中,因此,按照通用的C ++约定,您要告诉客户端代码将其忽略。

Now we give SBar two base classes, specialized on whether something is convertible to the non-template base of SZug : 现在,我们为SBar两个基类,专门针对某些东西是否可转换为SZug的非模板基:

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

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

Finally, we just need to make SBar a subclass of these bases (depending on the specialization): 最后,我们只需要使SBar成为这些基础的子类(取决于专业化):

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

Note that you don't specialize SBar here, you rather specialize the base classes. 请注意,您在这里不专门研究SBar ,而是专门研究基类。 This effectively gives the same effect, though. 但是,这有效地产生了相同的效果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM