c++ - 在类范围内将指针传递给 constexpr 函数时是否滥用推断父模板的参数

标签 c++ language-lawyer constexpr incomplete-type template-argument-deduction

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

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]提示 ParentKid 匹配问题:

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]还编译代码。所以...这是一个错误还是我开始发疯了?

最佳答案

Clang 遵守法律条文。是的,Kid 派生自 Parent。但是这种关系只有在 Kid 是一个完全定义的类型时才能建立。嗯,[class.mem]/6 :

A class is considered a completely-defined object type ([basic.types]) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, noexcept-specifiers, and default member initializers (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

我们处于我强调的“否则”部分。即使我们正在处理指针,该类仍未被视为已定义,因此指针转换是有效的。 GCC 过于宽松。

关于c++ - 在类范围内将指针传递给 constexpr 函数时是否滥用推断父模板的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47854760/

相关文章:

c++ - std::is_invocable 的奇怪行为

c++ - 从 constexpr 处的 std::views::split 获取最后一个元素

c++ - 从值/引用映射分配给引用映射

c++ - 指向非静态成员函数 "formally"的指针不被视为指针

c++ - 您可以使用 using 将基类中的公共(public)成员重新声明为派生类中的私有(private)成员吗?

c++ - constexpr 构造函数在 GCC 在编译时评估时给出不同的结果

c++ - constexpr 构造函数中不能使用 constexpr 构造函数

c++ - Excel 调用 C++ 程序的函数

C++ 库输出

c++ - 如何(可移植地)在 C 和 C++ 中获取 DBL_EPSILON