C++17 模板推导指南未用于空参数集(版本 2)?
C++17 template deduction guide not used for empty parameter set (ver 2)?
在模板演绎指南未用于空参数集后C++17 模板演绎指南中遇到了另一个奇怪之处?(不幸的是,该错误 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81486 仍未在 GCC 主干中修复:():
#include <utility>
template <class T> struct success
{
T value;
constexpr success(T &&v)
: value(std::move(v))
{
}
constexpr success(const T &v)
: value(v)
{
}
};
template <> struct success<void>
{
};
template <class T> success(T /*unused*/)->success<T>;
success()->success<void>;
template<class T> struct foo
{
foo(success<void>) {}
};
int main(void)
{
auto a = success{5}; // works
auto b = success{}; // works
auto c = success{"hello"}; // works
auto d = success(5); // works
//auto e = success(); // FAILS on GCC 7.2!
auto f = success("hello"); // works
foo<void> g(success()); // FAILS
static_assert(std::is_same<decltype(a), success<int>>::value, "");
static_assert(std::is_same<decltype(b), success<void>>::value, "");
static_assert(std::is_same<decltype(c), success<const char *>>::value, "");
static_assert(std::is_same<decltype(d), success<int>>::value, "");
//static_assert(std::is_same<decltype(e), success<void>>::value, "");
static_assert(std::is_same<decltype(f), success<const char *>>::value, "");
return 0;
}
至少对我来说,令人惊讶的是,foo<void> g(success());
未能在 clang 6.0 主干和 GCC 7 主干上使用模板扣除指南,如您在 https://godbolt.org/g/7m1Zhk 中看到的那样
我觉得这令人惊讶,而不是人们所期望的。模板指南说,一个朴素的success()
应按success<void>
建造。这应该适用于 foo 的明确构造函数接受success<void>
。相反,clang 6.0 主干报告:
34 : <source>:34:17: error: use of class template 'success' requires template arguments; argument deduction not allowed in function return type
foo<void> g(success()); // FAILS
^~~~~~~
3 : <source>:3:27: note: template is declared here
template <class T> struct success
^
GCC 7.3 主干报告:
<source>: In function 'int main()':
34 : <source>:34:25: error: 'auto' parameter not permitted in this context
foo<void> g(success()); // FAILS
^
谁能解释一下这里发生了什么?这是 C++ 17 标准的缺陷吗?
我相信你已经遇到了一种最令人烦恼的解析的新形式。
请记住,任何代码段的语法形式都是在名称查找以外的任何语义规则应用于它之前确定的。 现在模板名称在语法上是一个有效的简单类型说明符,可以解析
foo<void> g(success());
作为对象的定义g
初始值设定项或函数的声明g
. 根据最烦人的解析规则,函数解析"获胜",因此g
声明一个返回foo<void>
的函数,其一个未命名的参数是一个没有参数的函数,返回占位符类模板类型success
。
但是,当语义检查确实启动时,这不是类模板占位符类型的有效用法之一,因此程序格式不正确。
请注意,如果我们进行一些调整以避免最烦人的解析,则 clang 将成功:
foo<void> g2{success()};
struct bar { bar(int, succeed<void>) {} };
bar g3(1, success());
但是,我认为以下双括号技巧也应该有效,但它只会导致来自 clang 的新错误消息。 我不确定这个是怎么回事:
foo<void> g4((success()));
这是最令人烦恼的解析。
foo<void> g(success()); // FAILS
是一个名为g
的函数的声明,它返回一个foo<void>
,并将指向返回success
的空函数的指针类型为 [unnamed] 参数。
但是,success
不是一个类型,它是一个模板名称,不能将模板名称用作函数的返回类型,只能使用完整类型。因此,错误。
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 作为模板类型参数,为什么 type[N] 与其专用版本不匹配----模板<类 T>类 S<T[]>
- C++14 及更高版本是否允许 Lambda 函数的默认参数?如果是这样,怎么办?
- 如何创建一个版本的 boost::range::transform,该版本具有用于捕获上下文的额外参数
- 根据运行时参数调用模板函数的不同版本
- 无法使用 std::function 作为参数类型(需要函数指针版本)宁愿像 STL 这样的模板,但随后它无法推断参数
- CUDA9.2及以上版本中模板默认参数存在无法解决的外部函数错误
- 由于允许哪个版本的C++默认参数
- c++ 编译器优化是否可以针对布尔参数生成两个版本的函数
- C++17 模板推导指南未用于空参数集(版本 2)?
- 当模板参数为std::vector时,如何创建此方法的模板版本
- 为什么参数匹配适用于非模板版本,但不适用于模板版本
- const参数的类的只读版本
- 简短版本:错误 14 错误 C2660:'Player::addSpell':函数不接受 1 个参数
- 以不同方式实现可变参数构造函数的模板类:每个版本的优点和缺点是什么
- 同一方法签名的模板化和显式参数类型版本
- 从指针到具有常量和非常量版本的成员函数的模板参数推导
- 模板版本参数
- 创建我的.exe的批处理版本,它接受命令行参数(ParamCount(), ParamStr()和BCB 4.0中的Fi
- c++重载函数调用带有更多参数的自身版本