在范围符合规范N4622的Same
概念被定义为采取两种类型T
和U
,但有时用作内requires
只有一个这样的:
{ t } -> Same<T>;
Run Code Online (Sandbox Code Playgroud)
能够扣除第二种类型的规则是什么U
?(例如来自Concepts spec N4630)
最简单的类似例子是:
template <class T, class U>
concept bool C = (sizeof(T) == sizeof(U)) && (sizeof(U) != 1);
template <class T>
concept bool D = requires(T t){
// How is U deduced here?
{t} -> C<T>;
};
template <class T>
requires D<T>
void fn() {}
int main() {
// Fails with: unable to deduce placeholder type 'C<char>' from 't'
// That's expected.
//fn<char>();
// But how does this work?
fn<int>();
}
Run Code Online (Sandbox Code Playgroud)
使用g ++ 8.0.0和-fconcepts测试样本.
快速回顾一下,以确保我们\xe2\x80\x99都在同一页面上:占位符类型几乎是一种类型,但不完全是一种类型。它\xe2\x80\x99 是将被有效推导的类型的替代。(类似地,也有占位符非类型 [resp. 模板],它们是非类型的替代品。为了避免偏离正题,我\xe2\x80\x99ll 只是在这里提到它们的存在并使用包罗万象的占位符术语今后。)
\n\n在概念之前,我们唯一的占位符是auto
和decltype(auto)
说明符:
// the specifiers are all placeholders for `int`\nauto i = 42;\nauto& lref = i;\nauto&& rref = 0;\ndecltype(auto) = 2 * i;\n
Run Code Online (Sandbox Code Playgroud)\n\n通过概念,我们可以以更复杂的方式使用占位符:
\n\n// two placeholders for `int`\nstd::pair<auto, auto> p = std::make_pair(1, 4);\n\n// one placeholder\nstd::pair<auto, int> q = p;\n
Run Code Online (Sandbox Code Playgroud)\n\n这里\xe2\x80\x99s 变得棘手:概念本身可以用作占位符:
\n\ntemplate<typename Int>\nconcept bool Integral = \xe2\x80\xa6;\n\n// placeholder for `int` constrained by `Integral<int>`\nIntegral a = 0;\n\n// same as above\nIntegral<> b = a;\n\ntemplate<typename Lhs, typename Rhs>\nconcept bool EqualityComparable = \xe2\x80\xa6;\n\n// another placeholder for `int`\n// this time constrained by `EqualityComparable<int, double>`\nEqualityComparable<double> c = a;\n
Run Code Online (Sandbox Code Playgroud)\n\n仔细阅读二进制EqualityComparable
示例。使概念作为占位符变得棘手的是,第一个概念参数经过特殊处理,并且不会在参数列表中提及。尖括号列表中出现的任何参数(如果有)都对应于后续参数。
让\xe2\x80\x99s 为具有size()
. 为了演示,我们\xe2\x80\x99 将期望此size()
操作的结果应该可用作Incrementable
变量(而不是像Integral
概念这样的有意义的东西)。
template<typename Incr>\nconcept bool Incrementable = requires(Incr incr) {\n ++incr;\n};\n\ntemplate<typename Cont>\nconcept bool Sizeable = requires(Cont const cont) {\n // requirement #1\n { cont.size() } -> Incrementable\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n我们的要求#1 是一种特殊类型的复合要求。也就是说,它是一个占位符出现在语法Trailing-return-type中的类型。效果就像我们写的一样:
\n\ntemplate<Incrementable Incr>\nvoid valid_for_incrementable(Incr incr);\n\ntemplate<typename Cont>\nconcept bool Sizeable = requires(Cont const cont) {\n cont.size();\n valid_for_incrementable(cont.size());\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n简单地说,复合需求的目的是同时引入两个约束:括号中的表达式是有效的,并且它可以用作发明的约束验证函数模板的参数。
\n\n凭借我们对占位符及其在复合需求中的用途的了解,我们可以找到答案:
\n\ntemplate<typename T>\nconcept bool Demo = requires(T t) {\n { t } -> C<T>;\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n有效意味着我们C<T, T>
对t
表达式引入了约束。如果占位符是C<int>
相反的,那么约束也会是C<T, int>
相反的,依此类推。
归档时间: |
|
查看次数: |
1062 次 |
最近记录: |