【问题标题】:Template class with template constructor specialization for initializing a templated base class具有模板构造函数特化的模板类,用于初始化模板化基类
【发布时间】:2021-04-23 00:14:04
【问题描述】:

我有一个带有 bool 类型模板参数的模板基类。这个基类的构造函数参数列表取决于模板参数是真还是假。我想从这个类派生另一个模板类,其模板参数是任何类型。我需要这个派生类根据该类型的特征调用该基类的正确构造函数。

以下示例并非包罗万象。无论是否完整,基类模板 bool 都可以用于任何类型特征。此外,传递给派生类的模板参数的类型可以是任何类型。

我已经尝试了几种不同的方法来尝试语法化这个东西,但我得到的最接近的是下面的代码。然而,由于派生类需要完全专门化,它会出错。

#include <type_traits>
using namespace std;

template<bool IsIntegral> struct Base 
{
    template<bool IsI = IsIntegral,
        typename I = typename enable_if<IsI>::type>
    Base(int param) {}

    template<bool IsI = IsIntegral,
        typename I = typename enable_if<!IsI>::type>
    Base() {}
};

template<class T> class CL :
    Base<is_integral<T>::value>
{
public:
template<bool U = is_integral<T>::value> CL();

};

template<>
template<class T>
CL<T>::CL<true>() : // error: ISO C++ forbids declaration of ‘CL’ with no type [-fpermissive]
                    // CL<T>::CL<true>() :
                    //                 ^
                    // error: non-type partial specialization ‘CL<true>’ is not allowed
                    // error: no declaration matches ‘int CL<T>::CL()’
                    // CL<T>::CL<true>() :
                    // ^~~~~
    Base(4) { }

template<>
template<class T>
CL<T>::CL<false>()  // error: ISO C++ forbids declaration of ‘CL’ with no type [-fpermissive]
                    // CL<T>::CL<true>() :
                    //                 ^
                    // error: non-type partial specialization ‘CL<true>’ is not allowed
                    // error: no declaration matches ‘int CL<T>::CL()’
                    // CL<T>::CL<true>() :
                    // ^~~~~
    { }

int main () {
    // Base<true> a; // won't compile as expected
    Base<true> a(4);
    // Base<false> b(4); // won't compile as expected
    Base<false> b;
    
    CL<int> c; // integral
    CL<int*> d; // non-integral
    // should work for any types other than int and int*

    return 0;
}

我需要保持 T 类型是通用的,并且不能完全专门化 CL 类。什么是正确的语法?有解决办法吗?

我使用的是 gcc-g++ 版本 8.3.0-6。

提前致谢!

【问题讨论】:

    标签: c++ templates inheritance specialization


    【解决方案1】:

    在玩了一会儿之后,我想出了这个,我猜它属于“解决方法”的范畴,你愿意考虑:

    template<class T> class CL :
        Base<is_integral<T>::value>
    {
    public:
        CL() : CL{ is_integral<T>{} } {}
    
        template<typename U=T>
        CL(std::true_type) : Base<true>{4} {}
    
        template<typename U=T>
        CL(std::false_type)
        {
        }
    };
    

    【讨论】:

    • 这是一个不错的方法(不是太多的“解决方法”恕我直言),但您通常希望将委托构造函数设为私有,而且除非您打算将它们设为模板为虚拟模板参数U 应用 SFINAE。最后,为了确保我们确实调用了我们继承自的基本构造函数,我们可以使用注入的类名而不是显式地提供模板参数列表(CL::Base{4} 而不是Base&lt;true&gt;{4})。供其他人参考,这种技术通常称为标签调度。
    • 这很好用!感谢您的快速反应。我什至尝试在没有警告的情况下在不同的 C++ 标准(11、14 和 17)上编译它。太棒了!
    【解决方案2】:

    你的派生类应该是:

    template<class T> class CL :
    Base<is_integral<T>::value>{
      public:
         using base_t = Base<is_integral<T>::value>;
         using base_t::base_t;
    };
    

    using base_t::base_t; 让您从基类继承构造函数(从 c++11 开始可用)。

    在您的示例中,您还应该更改:

    CL<int> c; // integral
    

    进入,例如:

    CL<int> c(10); // integral
    

    【讨论】:

    • 请注意,OP 在这两种情况下都需要默认构造函数,但是在积分特征持有的情况下,希望使用常量(或者说,基于特征的)值转发到基本构造函数。
    【解决方案3】:

    C++20 和要求子句

    在 C++20 之前,我建议将标签分派给私有委托构造函数,如 @SamVarshavchik's answer 所示。

    一旦您可以使用 C++20,您就可以使用 requires 子句轻松构建这些关系:

    #include <type_traits>
    
    template <bool IsIntegral>
    struct Base  {
        Base(int param) requires IsIntegral {}
        Base() requires (!IsIntegral) {}
    };
    
    template<typename T> 
    class CL : Base<std::is_integral<T>::value> {
        static constexpr bool kIsIntegral = std::is_integral_v<T>;
     public:
        CL() requires kIsIntegral : CL::Base(4) {}
        CL() requires (!kIsIntegral) : CL::Base() {}    
    };
    

    【讨论】:

    • 太棒了!我用标志 -std=c++2a 和 -fconcepts 编译了它,效果很好!不幸的是,我确实需要支持旧标准,但这是 C++20 的绝佳解决方案!
    猜你喜欢
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多