类模板专用化演绎是否应该考虑演绎指南参数初始化?
Should deduction guide argument initialization considered by class template specialization deduction?
作为这个问题的后续,我测试了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确实如此。哪个编译器是正确的?
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。
- 模板模板参数的演绎指南
- 使用显式模板参数列表和 [temp.arg.explicit]/3 的函数调用的演绎失败
- 类模板专用化演绎是否应该考虑演绎指南参数初始化?
- C++17模板演绎指南不用于空参数集?
- 演绎指南和具有可变参数模板构造函数的可变参数类模板 - 参数包长度不匹配
- 可变参数模板构造函数的演绎指南失败
- 模板作为函数模板的参数 - 演绎失败
- 是否可以保证模板模板参数调用用户提供的演绎指南
- 可变参数模板作为模板参数:演绎适用于 GCC,但不适用于 Clang
- 错误:没有匹配的函数调用[…]注意:模板参数演绎/替换失败
- 演绎模板参数c++
- 模板参数演绎/替换失败
- 如何帮助编译器演绎模板参数
- 从数组维数中演绎模板参数
- 为什么这个模板参数不可演绎?
- c++模板参数演绎失败
- 为什么模板参数演绎/替换在这里失败?
- 带有多个包的c++模板,按参数和返回值进行演绎
- 模板参数演绎失败
- 参数类型自动演绎和匿名lambda函数