在类的范围内传递指向constexpr函数的指针时,是否滥用推断父模板的参数

问题描述 投票:8回答:1

我得到的最小例子有点复杂:

struct A { };

template <int>
struct Parent { };

template <int N>
constexpr int operator*(A, Parent<N>*) { return N; }

template <class T>
using ptr = T*;

template <int>
struct Other { };

template <int N>
struct Kid: Parent<N> { 
    static Other<A{} * ptr<Kid>{}> o;
};

int main() {
    Kid<2>{};
}

[gcc]编译代码没有任何问题,[clang]抱怨Parent匹配Kid问题:

prog.cc:7:15: note: candidate template ignored: could not match 'Parent' against 'Kid'
constexpr int operator*(A, Parent<N>*) { return N; }

当我们稍微更改代码时更加荒谬:

struct A { };

template <int>
struct Parent { };

template <int N>
constexpr int operator*(A, Parent<N>*) { return N; }

template <class T>
using ptr = T*;

template <int>
struct Other { };

template <int N>
struct Kid: Parent<N> { 
    static constexpr int s = A{} * ptr<Kid>{};
};

int main() {
    Other<Kid<2>::s>{};
}

[clang]也编译代码。所以...这是一个错误还是我开始变得疯狂?

c++ language-lawyer constexpr incomplete-type template-deduction
1个回答
6
投票

Clang对法律条文是正确的。是的,Kid来自Parent。但只有在Kid是完全定义的类型时才能建立这种关系。好吧,[class.mem]/6

在类说明符的结束时,类被认为是完全定义的对象类型([basic.types])(或完整类型)。在类成员规范中,该类在函数体,默认参数,noexcept-specifiers和默认成员初始化器(包括嵌套类中的这类事物)中被视为完整。否则,它在其自己的类成员规范中被视为不完整。

我们强调了“其他”部分。即使我们处理指针,该类还没有被认为是指针转换有效。海湾合作委员会过于宽容。

© www.soinside.com 2019 - 2024. All rights reserved.