首页 > 解决方案 > 从具有自动参数的模板类继承时基类不明确

问题描述

给定代码

#include <type_traits>

template <auto I, class T>
struct C {};

template <auto I, class T>
void func(C<I, T> c)  {}

struct C2 : C<0, int>, C<0u, long> {};

int main() {
    static_assert(!std::is_same<C<0, int>, C<0u, long>>::value);

    C2 c2;
    func<0>(c2);  // Error

    return 0;
}

我收到错误(来自 GCC):

<source>:15:15: note:   'C<0, T>' is an ambiguous base class of 'C2'
   15 |     func<0>(c2);
      |               ^

当实例化 (和) 是明显不同的类型时,类模板 ( ) 怎么会C<I, T>是一个模棱两可的基类?C<0, int>C<0u, long>

编辑:我忘记了部分专业化。

标签: c++

解决方案


错误消息可能会稍微好一些。但问题在于尝试进行重载解决方案。理论上可以从 合成两个可能的重载C2

void func(C<0, int> c)  {}
void func(C<0u, long> c)  {}

这是因为类类型的参数可以与接受其基数之一的模板匹配。并且模板参数推导能够推导基类的模板参数。

但这里有个问题:编译器只允许从模板合成一个重载,那么它应该使用哪个基类来合成呢?这是模棱两可的,因此你的错误发生了。编译器不知道它应该使用哪个基类来为特化进行模板参数推导C。从这个意义上说,这些基础是模棱两可的。


您的编辑没有太大变化。您指定0,但这仍然可以匹配0u参数。为了匹配非类型模板参数,相应的模板参数必须是参数类型的转换常量表达式。0是一个常量表达式,可以转换为0u常量表达式,反之亦然。因此,指定0甚至0u作为显式参数都不会解决歧义。

但是,指定intorlong将解决歧义。所以我们可以重写:

template <class T, auto I>
void func(C<I, T> )  {}

然后打电话

func<int>(c2); 

推荐阅读