c++ - 未评估上下文中的默认模板参数和 lambda:错误还是功能?
问题描述
我们考虑使用完全相同的语法创建两种不同类型的目标。这可以使用 lambdas 轻松完成:
auto x = []{};
auto y = []{};
static_assert(!std::is_same_v<decltype(x), decltype(y)>);
但我们不是使用 lambda,而是寻找另一种更优雅的语法。这里有一些测试。我们首先定义一些工具:
#include <iostream>
#include <type_traits>
#define macro object<decltype([]{})>
#define singleton object<decltype([]{})>
constexpr auto function() noexcept
{
return []{};
}
template <class T = decltype([]{})>
constexpr auto defaulted(T arg = {}) noexcept
{
return arg;
}
template <class T = decltype([]{})>
struct object
{
constexpr object() noexcept {}
};
template <class T>
struct ctad
{
template <class... Args>
constexpr ctad(const Args&...) noexcept {}
};
template <class... Args>
ctad(const Args&...) -> ctad<decltype([]{})>;
和以下变量:
// Lambdas
constexpr auto x0 = []{};
constexpr auto y0 = []{};
constexpr bool ok0 = !std::is_same_v<decltype(x0), decltype(y0)>;
// Function
constexpr auto x1 = function();
constexpr auto y1 = function();
constexpr bool ok1 = !std::is_same_v<decltype(x1), decltype(y1)>;
// Defaulted
constexpr auto x2 = defaulted();
constexpr auto y2 = defaulted();
constexpr bool ok2 = !std::is_same_v<decltype(x2), decltype(y2)>;
// Object
constexpr auto x3 = object();
constexpr auto y3 = object();
constexpr bool ok3 = !std::is_same_v<decltype(x3), decltype(y3)>;
// Ctad
constexpr auto x4 = ctad();
constexpr auto y4 = ctad();
constexpr bool ok4 = !std::is_same_v<decltype(x4), decltype(y4)>;
// Macro
constexpr auto x5 = macro();
constexpr auto y5 = macro();
constexpr bool ok5 = !std::is_same_v<decltype(x5), decltype(y5)>;
// Singleton
constexpr singleton x6;
constexpr singleton y6;
constexpr bool ok6 = !std::is_same_v<decltype(x6), decltype(y6)>;
和以下测试:
int main(int argc, char* argv[])
{
// Assertions
static_assert(ok0); // lambdas
//static_assert(ok1); // function
static_assert(ok2); // defaulted function
static_assert(ok3); // defaulted class
//static_assert(ok4); // CTAD
static_assert(ok5); // macro
static_assert(ok6); // singleton (macro also)
// Display
std::cout << ok1 << std::endl;
std::cout << ok2 << std::endl;
std::cout << ok3 << std::endl;
std::cout << ok4 << std::endl;
std::cout << ok5 << std::endl;
std::cout << ok6 << std::endl;
// Return
return 0;
}
这是使用当前主干版本的 GCC 编译的,带有 options -std=c++2a
。在编译器资源管理器中查看结果。
事实上ok0
,ok5
和ok6
工作并不是一个惊喜。ok2
然而, and ok3
are true
while的事实ok4
对我来说并不令人惊讶。
- 有人可以解释制定
ok3
true
but的规则ok4
false
吗? - 它真的应该如何工作,或者这是一个关于实验性功能的编译器错误(未评估上下文中的 lambdas)?(非常欢迎参考标准或 C++ 提案)
注意:我真的希望这是一个特性而不是一个错误,只是因为它使一些疯狂的想法可以实现
解决方案
有人可以解释使 ok3 为真但 ok4 为假的规则吗?
ok3 是真的,因为使用 lambdas 类型作为默认类型。
lambda 表达式的类型(也是闭包对象的类型)是唯一的、未命名的非联合类类型,
因此,默认模板类型为object
,模板参数类型为macro
并且singltone
每次实例化后总是不同的。但是,对于函数function
调用,返回的 lambda 是唯一的,并且它的类型是唯一的。模板函数ctad
只有参数的模板,但返回值是唯一的。如果重写函数为:
template <class... Args, class T = decltype([]{})>
ctad(const Args&...) -> ctad<T>;
在这种情况下,每次实例化后返回类型都会不同。
推荐阅读
- javascript - Angular 9 a for 循环正在向空属性名称添加值
- c++ - 如何在 Windows 内核中获取文件大小
- python - 这段代码如何生成 26 次唯一字符?
- python - 为什么文件中的这个打印会添加我没有要求的换行符?
- autohotkey - 在 onenote 2016 中折叠展开的 autohotkey 脚本
- flutter - 停留在 Flutter Native Plugin 指南中的第 2b 步
- python - 使用 Python 生成所需的数字组合
- python-3.x - 单击按钮时,我的 gui 未打印所需的用户名
- python - 如何在 discord.py 中使字符串长于 1 个单词?
- algorithm - 使用“Low-Down Triple Dealing”魔术技巧来确定牌在牌组中的位置的算法是什么