首页 > 解决方案 > 类模板专业化推导是否应该推导引导参数初始化?

问题描述

作为这个问题的后续,我测试了 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++ 标准[over.match.class.deduct]/2的这一段中定义:

初始化和重载解析按照 [dcl.init] 和 [over.match.ctor]、[over.match.copy] 或 [over.match.list] 中的描述执行(根据执行的初始化类型)假设类类型的对象,其中选定的函数和函数模板被认为是该类类型的构造函数,以形成重载集,[...]

我强调“为了形成重载集”,因为我认为这是 clang 和 gcc 分歧的地方。Clang 似乎没有检查推导指南假设的构造函数是否是一个可行的函数,但 gcc 可以。哪个编译器是对的?

标签: c++language-lawyerc++17template-argument-deduction

解决方案


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

实际上,演绎指南一个可行的功能。一个函数是可行的只是意味着参数的数量匹配,约束得到满足,并且您可以为每个参数/参数对形成隐式转换序列。当我们检查 ICS 是否存在时,[over.best.ics]/2

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

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

例如,gcc 和 clang 都拒绝这个程序。#1是一个可行的候选者,并且它是最好的候选者,尽管删除了复制构造函数:

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);
}

但是我们从来没有真正调用我们用于推导的合成函数和函数模板。我们只是在执行重载决议并选择最佳候选者——我们只是用来选择类类型,然后我们重新开始。我们在任何时候都不应该真正需要复制。

我认为这是一个 gcc 错误。归档86439 。


推荐阅读