模板参数推导顺序

Template argument deduction order

本文关键字:顺序 参数      更新时间:2023-10-16

>谁能解释为什么下面的代码不能编译:

template <typename P>
struct Base
{
    friend typename P::One;
    friend typename P::Two;
    friend typename P::Three;
};
template<typename U, typename D, typename T>
struct Derived : public Base<Derived<U,D,T>>
{
    using One   = U;
    using Two   = D;
    using Three = T;
};

错误是:

..PRPmain.cpp:3:1: error: no type named 'One' in 'struct Derived<A, B, C>'
 {
 ^
..PRPmain.cpp:3:1: error: no type named 'Two' in 'struct Derived<A, B, C>'
..PRPmain.cpp:3:1: error: no type named 'Three' in 'struct Derived<A, B, C>'

以及为什么以下代码可以完美编译:

template <typename T>
struct Sum
{
    constexpr static int sze = T::uno + T::due + T::tre;
};
template<int i, int j, int k>
struct Triple : public Sum<Triple<i, j, k>>
{
    constexpr static int uno = i;
    constexpr static int due = j;
    constexpr static int tre = k;
};

两者之间有什么区别?我认为这与模板扣除顺序有关,但我可能是错的。

我在 Win4.8 上使用 MinGW 7,并打开标志 C++11。谢谢!

您的代码中没有发生模板参数推导,因此这与推导无关。

该问题是由于尝试使用 Derived 的成员而导致的,而它是不完整的类型。

Derived的基类列表中发生的Base<Derived<U,D,T>>实例化期间,编译器会立即处理友元声明,此时Derived不完整,因此无法尝试使用其成员。

Sum中的静态成员不会自动实例化,并且在 Triple 的声明中不需要。如果稍后使用静态成员,则Triple是一个完整的类型,可以引用其成员。

如果您尝试在Sum的定义中使用Sum<T>::sze,则会收到类似的错误,因为此时T不是完整的类型:

template <typename T>
struct Sum
{
    constexpr static int sze = T::uno + T::due + T::tre;
    char buf[sze];
};
template<int i, int j, int k>
struct Triple : public Sum<Triple<i, j, k>>
{
    constexpr static int uno = i;
    constexpr static int due = j;
    constexpr static int tre = k;
};
Triple<1, 2, 3> t;