在类模板中专门化非静态成员是不可能的吗?为啥?

Posted

技术标签:

【中文标题】在类模板中专门化非静态成员是不可能的吗?为啥?【英文标题】:Is it impossible to specialize non-static members in a class template? Why?在类模板中专门化非静态成员是不可能的吗?为什么? 【发布时间】:2021-08-24 14:31:45 【问题描述】:

背景

我有一个类,我已经模板化了通过继承获得编译时多态性作为运行时多态性的替代方案。

我对这个类中的一些方法有两种不同的特化。我们称他们为T_aT_b

问题

我想根据模板参数用不同的值初始化这个类的一个常量但非静态的对象数组。

template<class T>
class A 
    const anotherObject& aO;
    const ConfigPar configPars[];

无效尝试

专业化

首先,我认为我可以专门化成员:

template<class T>
class A 
    const ConfigPar configPars[];

    A(T t);


template<>
const ConfigPar A<T_a>::configPars[] 
        anotherObject.foo1, "bar1",
        anotherObject.foo2, "bar2",


template<>
const ConfigPar A<T_b>::configPars[] 
        anotherObject.foo1, "bar1",
        anotherObject.foo2, "bar2",
        anotherObject.foo3, "bar3",

但是,这不起作用,因为显然您只能专门化静态类成员。但是,configPars 数组中对象的值依赖于另一个实例成员,所以我不能将configPars 设为静态。

构造函数重载

接下来,我想重载A的构造函数,只是在构造函数中以不同的方式初始化configPars

template<class T>
class A 
    const ConfigPar configPars[];

    A(T_a t) : configPars
            anotherObject.foo1, "bar1",
            anotherObject.foo2, "bar2",
     

    A(T_b t) : configPars
            anotherObject.foo1, "bar1",
            anotherObject.foo2, "bar2",
            anotherObject.foo3, "bar3",
     

但是,在此我的编译器抱怨error: too many initializers for 'const ConfigPar [0]'。显然我不能在声明中忽略数组的大小?

问题在于两个特化(或重载的构造函数,在这种情况下)之间的数组大小不同。

我该如何处理?

【问题讨论】:

const ConfigPar configPars[]; 不合法。所有类成员都必须具有定义的大小,这意味着数组大小必须在类定义中已知。您可以使用 const std::vector&lt;ConfigPar&gt; 代替它。 @NathanOliver 我明白了。是否无法根据模板参数定义大小,例如在专业?这是嵌入式的(在微控制器上运行),所以很遗憾我无法访问标准库的 std:: 容器。 【参考方案1】:

在类定义中必须知道所有类成员的大小。这包括数组成员的大小。您可以做的是根据 T 是什么来确定您拥有的数组大小,并在定义中提供它。可能看起来像

template<class T>
class A 
    const ConfigPar configPars[(std::is_same_v<T, T_a> ? 2 : 3)]; // 2 for T_a, 3 otherwise

    A(T t);
;

// specialization of constructor for T_a
template<>
A<T_a>::A(T_a t) : configPars
        1, "bar1",
        2, "bar2",


    // constructor body, use t here


// specialization of constructor for T_b
template<>
A<T_b>::A(T_b t) : configPars
        1, "bar1",
        2, "bar2",
        3, "bar3",


    // constructor body, use t here

【讨论】:

这是一个优雅的解决方案,但是,这是嵌入的,所以很遗憾type_traits 对我不可用。 (对不起,忘了在我的问题中提及) @Compizfox 好消息是,您不需要它们。 std::is_same 自己很容易实现。您甚至可以从 here 复制一个实现。

以上是关于在类模板中专门化非静态成员是不可能的吗?为啥?的主要内容,如果未能解决你的问题,请参考以下文章

java中为啥说静态方法先执行?

静态方法与非静态方法的区别

静态方法和非静态方法的区别

为啥静态成员函数只能在类定义中声明为静态,而不能在其自己的定义中声明?

类定义中的静态数据成员初始化?

c# 在类嵌套结构中引用非静态类成员