带有 lambda 作为每个实例化的唯一默认参数的模板

Posted

技术标签:

【中文标题】带有 lambda 作为每个实例化的唯一默认参数的模板【英文标题】:template with lambda as unique default parameter on each instantiation 【发布时间】:2019-06-21 23:01:10 【问题描述】:

我正在寻找一种在每次实例化模板时自动使默认模板参数唯一的方法。由于 lambda 表达式创建的未命名函数对象具有不同的类型,我想以某种方式采用它们。随着最近对标准 daft 的更改删除了 “lambda 表达式不应出现在...模板参数” 限制(请参阅Wording for lambdas in unevaluated contexts),这似乎是个好主意。所以我写了以下有点工作的sn-p compiles on recent gcc and clang:

#include <type_traits>

template<void ( * ) (void) = []()> class
unique final ;

static_assert(false == ::std::is_same_v<unique<>, unique<>>);

int main()

    return 0;

这是一种可行的方法还是那些“格式不正确,不需要诊断”的案例之一?

一些额外的上下文:我想用它来实现应该在单个翻译单元中工作的 Ada 风格的强类型定义,而无需手动发明否则将不使用的唯一标签:

struct _tag_WowInt ;
using Int = type<int, _tag_WowInt>;
struct _tag_SoUnique ;
using DifferentInt = type<int, _tag_SoUnique>;

Upd1:我想提一下,涉及__COUNTER__ 或类似宏的方法在一般情况下不起作用,因为它们只会被预处理器扩展一次并且won't yield unique types when used inside of template for example。

【问题讨论】:

msvc 和 edg 甚至出于不同的原因拒绝您的代码;有趣。 【参考方案1】:

我相信你是对的,在我看来这是“格式错误,不需要诊断”。我认为这是由 [temp.res/8.4] 和 [temp.res/8.5]:

(8.4) —— 紧随其定义的模板的假设实例化将是错误的,因为 不依赖于模板参数的构造,或

(8.5) ― 在假设实例化中对这种构造的解释与解释不同 模板的任何实际实例化中的相应构造。 [注意:这可能发生在以下情况:

(8.5.1) ― 在非依赖名称中使用的类型在定义模板时是不完整的,但在执行实例化时是完整的,或者

(8.5.2) ― 在模板定义中查找名称时发现了一个 using-declaration,但在实例化的相应范围内查找却没有找到任何声明,因为 using-declaration 是一个包扩展,而对应的包是空的,或者

(8.5.3) ― 实例化使用在定义模板时尚未定义的默认参数或默认模板参数,或

(8.5.4) ― 模板实例化使用中的常量表达式求值

(8.5.4.1) ― 整数或无范围枚举类型的 const 对象的值或

(8.5.4.2) ― constexpr 对象的值或

(8.5.4.3) ― 引用的值或

(8.5.4.4) ― constexpr 函数的定义, 并且在定义模板时未定义该实体,或者

(8.5.5) ― 由非依赖 simple-template-id 指定的类模板特化或变量模板特化被模板使用,或者它是从未定义的部分特化实例化的模板已定义,或者它命名了在定义模板时未声明的显式特化。 — 尾注]

即使您的用例未在注释示例中明确列出,但在我的理解中,该要求意味着unique&lt;&gt; 必须在整个程序中引用相同的东西,否则它是不正确的,不需要诊断.

这是CWG1850。委员会似乎不喜欢这个 一种有状态的元编程。 constexpr counter 不再有效 在较新版本的编译器中。

【讨论】:

8.4 似乎根本不适用。哪个不依赖于模板参数的构造在这里格式不正确?我也不确定8.5。 1)那里引用的“构造”似乎是指模板的某些部分,而不是模板实例化; 2)允许使用默认参数实例化模板在不同的范围内产生不同的结果,因为默认模板参数可能会被重新定义(例如,当用作模板模板参数时)。 @VTT 8.4 不适用,但它定义了“假设的实例化”是什么。 @VTT 您链接的论文有一个较新版本 (P0315R4),作者声称在两个 TU 中定义 foo&lt;[]&gt;() 应该违反 ODR。 @VTT 有趣的是,在 GCC 中继中 template&lt;typename = decltype([])&gt; class unique 总是产生相同的类型 (godbolt.org/z/SO1PZl)。 @Rakete1111 我明白了。这样就可以做出疯狂的事情:wandbox.org/permlink/ACtX4SdSJqc2MOHz

以上是关于带有 lambda 作为每个实例化的唯一默认参数的模板的主要内容,如果未能解决你的问题,请参考以下文章

Lambda 作为函数参数

C++ - 为任何 lambda 创建一个实例化桶

Kotlin函数 ⑥ ( 函数参数为 Lambda 表达式 | Lambda 表达式作为参数的简略写法 | 唯一参数的简略写法 | 最后一个参数的简略写法 )

Python的带有下划线的lambda作为参数?

如何在 Qt 5 中使用带有实例化的 VAO

将 lambda 作为模板参数传递给函数指针函数模板化