模棱两可的部分专业化取决于std :: enable_if

Ambiguous partial specialization depending on std::enable_if

本文关键字:enable if std 取决于 专业化 模棱两可      更新时间:2023-10-16

我有以下代码:

#include <iostream>
template <class T, typename U = void> class A;
template <class T>
class C
{
public:
    typedef T Var_t;
};
template <class T>
class B : public C<T>
{
};
template <class T>
class A<B<T>>
{
public:
    A() { std::cout << "Here." << std::endl; }
};
template <class T>
class A<T, typename std::enable_if<
                             std::is_base_of<C<typename T::Var_t>, T>::value>
                             ::type>
{
public:
    A() { std::cout << "There." << std::endl;}
};
int main() 
{
    A<B<int>> a;
    return 0;
}

编译器尝试使用参数B<int>实例化第二部分专业化时,std::is_base_of<C<int>, B<int>>::valuetrue,因此std::enable_if<...>::type返回void(如果未指定默认类型)。这会导致"模棱两可的部分专业化"错误,因为编译器无法在第一部分和第二部分专业方面做出决定。到目前为止,一切都很好。但是,当我将std::enable_if中的代码替换为true(即第二部分专业化只是template <class T> class A<T, typename std::enable_if<true>::type>)时,代码编译并运行。它输出"Here",表明选择了第一个专业化。

我的问题是:如果他们都对void进行评估,为什么std::enable_if<true>::type的行为与std::enable_if<std::is_base_of<...>::value>::type的行为不同?

此行为已在此处的IDEONE上进行了测试和验证。

std::enable_if<true>::type中,您的代码定义了A类A的两个专业:

  1. A<B<T>, void>
  2. A<T, std::enable_if<true>::type>

这两个专业彼此之间完全不同。第一个专业化狭窄地集中在B<T>型,而第二个专业化完全拟合了任何类型。同样,在第二个专业化中,std::enable_if表达式不取决于T

对于任何声明A<X> a;X类型将匹配B<something>。如果与B<something>匹配,则将使用第一个专业化,因为它是"更专业的"。如果X不匹配B<something>,则将使用第二个更通用的专业化。无论哪种方式,您都不会遇到模棱两可的错误。

有关更多详细信息,请参见部分模板专业化中的部分顺序的讨论

现在让我们考虑std::enable_if<std::is_base_of<...>::value>::type案例。

您仍然有两个专业化

  1. A<B<T>, void>
  2. A<T, std::enable_if<...>>

类型B<int>现在匹配两个专业(一定程度)。显然,它与A<B<T>>, void>专业化匹配,但也与A<T, std::enable_if...>>专业化匹配,因为B<int>是一种满足std::enable_if表达式所施加的条件的类型。

为您提供两个同等有效的专业,这是您声明可变a的候选人,因此您会得到"模棱两可的部分专业化"错误。

,如果您在main中添加了另外两个声明,这可能会使所有这些都更具体。

A<C<int>> x;
A<int>    y;

std::enable_if<true>情况下,这将编译,两个声明都将称为"那里"构造函数。

在更复杂的情况下,x的声明将编译并调用"那里"构造函数,但y的声明将会有一个编译器错误。

没有int::Var_t,因此std::enable_if表达式将替换失败,Sfinae将隐藏该专业化。这意味着不会有任何适合int的专业化,您将获得错误aggregate ‘A<int> y’ has incomplete type and cannot be defined