模板参数扣除顺序

nya*_*108 3 c++ templates c++11

任何人都可以解释为什么以下代码无法编译:

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;
};
Run Code Online (Sandbox Code Playgroud)

错误是:

..\PRP\main.cpp:3:1: error: no type named 'One' in 'struct Derived<A, B, C>'
 {
 ^
..\PRP\main.cpp:3:1: error: no type named 'Two' in 'struct Derived<A, B, C>'
..\PRP\main.cpp:3:1: error: no type named 'Three' in 'struct Derived<A, B, C>'
Run Code Online (Sandbox Code Playgroud)

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

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;
};
Run Code Online (Sandbox Code Playgroud)

两者有什么不同?我认为这与模板演绎顺序有关,但我可能是错的.

我在Win7上使用MinGW 4.8,标志为C++ 11.谢谢!

Jon*_*ely 8

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

问题是由于尝试使用Derived不完整类型的成员而引起的.

编译器在实例化Base<Derived<U,D,T>>时会立即处理好友声明,这些声明在基类列表中发生Derived,并且此时Derived不完整,因此尝试使用其成员是不可能的.

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

如果您尝试Sum<T>::sze在定义中使用,Sum则会得到类似的错误,因为此时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;
Run Code Online (Sandbox Code Playgroud)