类模板专业化推导是否应该考虑推导指导参数初始化?

2024-03-11

作为此的后续question https://stackoverflow.com/q/51235025/5632316,我测试了 clang 和 gcc 的行为。看来两个编译器对 C++ 标准有不同的解释。

在下面的示例中,如果需要根据推导指南假设构造函数参数复制不可复制的参数,GCC 将拒绝编译。 Clang 不执行此检查:

#include <cstddef>

struct not_copyable{
    not_copyable()=default;
    not_copyable(const not_copyable&)=delete;
};
struct movable{
    movable()=default;
    movable(movable&&);
};

template <typename T, size_t N>
struct A
 { template <typename ... Ts> A (Ts const & ...) {} };

template <typename T, size_t N>
struct B
 { template <typename ... Ts> B (const Ts & ...) {} };

template <typename T, typename ... Ts>
A(T const &, Ts const & ...) -> A<T, 1U + sizeof...(Ts)>;

template <typename T, typename ... Ts>
B(T, Ts ...) -> B<T, 1 + sizeof...(Ts)>;


int main()
 {
   not_copyable nc;
   movable m;

   auto a0 = A{nc};    // gcc & clang -> compile
   auto a1 = A{m};     // gcc & clang -> compile
   auto b0 = B{nc};    // clang ->compile;  gcc -> error
   auto b1 = B{m};     // clang ->compile;  gcc -> error
 }

认为 C++ 标准的这一段中定义了正确的行为[超过.匹配.类别.扣除]/2 http://eel.is/c++draft/over.match.class.deduct#2:

初始化和重载决策的执行方式如下所述 [dcl.init] 和 [over.match.ctor]、[over.match.copy] 或 [over.match.list](适合初始化类型 执行)对于假设类类型的对象,其中 选定的函数和函数模板被认为是 该类类型的构造函数为了形成过载 放,[...]

我强调“为了形成过载集“因为我认为这就是 clang 和 gcc 的分歧之处。Clang 似乎没有检查推导指南假设构造函数是否是一个可行的功能 http://eel.is/c++draft/over.match.viable,但海湾合作委员会确实如此。哪个编译器是正确的?


Clang 似乎不会检查推导引导假设构造函数是否是可行的函数,但 gcc 会检查。

其实,推导指南is一个可行的功能。函数可行仅意味着参数数量匹配、满足约束,并且您可以为每个参数/参数对形成隐式转换序列。当我们检查 ICS 是否存在时,[超过最佳.ics]/2 http://eel.is/c++draft/over.best.ics#2.sentence-2:

其他属性,例如生命周期、存储类、对齐方式、参数的可访问性、参数是否为位字段,以及函数是否被删除,被忽略。

删除一个函数不会使其变得不可行,这一点非常重要,因为重要的是它最终仍然可以成为最佳可行的候选函数。这意味着事实是not_copyable的复制构造函数被删除应该只在我们实际调用它时才生效。

例如,gcc 和 clang 都拒绝该程序。#1 is a viable尽管删除了复制构造函数,但它是最佳可行的候选者:

struct NC {
    NC() = default;
    NC(NC const&) = delete;
    NC& operator=(NC const&) = delete;
};       

void foo(NC );                            // #1
template <typename T> void foo(T const&); // #2

int main() {
    NC nc;
    foo(nc);
}

但我们实际上从来没有invoking我们用于推导的合成函数和函数模板。我们只是执行重载解析并选择最佳候选者 - 我们仅使用它来选择类类型,然后我们重新开始。我们在任何时候都不应该真正要求复制。

我认为这是一个 gcc 错误。提起86439 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86439.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

类模板专业化推导是否应该考虑推导指导参数初始化? 的相关文章

随机推荐