使用概念禁用非模板方法
Disable non-templated methods with concepts
是否有限制非模板化方法的语法?我在带有 clang 概念分支和 gcc 的 godbolt 上尝试过的所有语法都无法编译:
// these examples do not compile
template <bool B>
struct X
{
requires B
void foo() {}
};
template <class T>
struct Y
{
requires (std::is_trivially_copyable_v<T>)
auto foo() {}
};
使其编译的技巧与您在 SFINAE 中需要做的技巧相同,即制作方法模板,即使它们实际上不是模板。有趣的是,约束似乎不需要方法模板,它可以单独在 class 模板上正常工作,所以我真的希望有一种方法可以通过概念应用约束,而不必求助于老技巧:
// old hacks
template <bool B>
struct X
{
template <bool = B>
requires B
auto foo() {}
};
template <class T>
struct Y
{
template <class = T>
requires std::is_trivially_copyable_v<T>
auto foo() {}
};
现实生活中的例子:
template <class T, bool Copyable_buf = false>
struct Buffer
{
/* ... */
requires Copyable_buf
Buffer(const Buffer& other) {}
/* ... */
};
template <class T>
using Copyable_buffer = Buffer<T, true>;
是的,有!! The requires clause 可以作为函数声明符的最后一个元素出现,在这种情况下它允许约束非模板方法(或与此相关的自由函数):
// This works as expected! Yey!!
template <class T, bool Copyable_buf = false>
struct Buffer
{
Buffer(const Buffer& other) requires Copyable_buf
{
// ...
}
};
template <bool B>
struct X
{
auto foo() requires B
{
// ...
}
};
template <class T>
struct Y
{
auto foo() requires std::is_trivially_copyable_v<T>
{
// ...
}
};
这个答案是经验性的,基于对当前概念实现的测试。 Godbolt test. 给出了确认此行为的标准报价。
为了支持其他答案,这里是最新标准草案中关于此的规范性措辞:
[dcl.decl]
1 A declarator declares a single variable, function, or type, within a declaration. The init-declarator-list appearing in a declaration is a comma-separated sequence of declarators, each of which can have an initializer.
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator initializeropt
declarator requires-clause
4 The optional requires-clause ([temp]) in an init-declarator or member-declarator shall not be present when the declarator does not declare a function ([dcl.fct]). When present after a declarator, the requires-clause is called the trailing requires-clause. The trailing requires-clause introduces the constraint-expression that results from interpreting its constraint-logical-or-expression as a constraint-expression. [ Example:
void f1(int a) requires true; // OK
auto f2(int a) -> bool requires true; // OK
auto f3(int a) requires true -> bool; // error: requires-clause precedes trailing-return-type
void (*pf)() requires true; // error: constraint on a variable
void g(int (*)() requires true); // error: constraint on a parameter-declaration
auto* p = new void(*)(char) requires true; // error: not a function declaration
— end example ]
如这两段所述,尾随的 requires 子句可以出现在函数声明符的末尾。它的意思是通过它接受作为参数(包括概念)的常量表达式来约束函数。
最近有关于此的更改。参见 https://github.com/cplusplus/nbballot/issues/374
它指出:
How constraints work with non-templated functions is still under heavy construction during this late stage in the process. While we have provided various comments that build in a direction where supporting such constructs (including ordering between multiple constrained functions based on their constraints) would become possible, we acknowledge that WG 21 might not find a solution with consensus in time for the DIS. We ask WG 21 to evaluate the risk of shipping the feature in such a state and consider removing the ability to declare such functions.
Does EWG want to consider this for C++20?
| F | A |
|----|----|
| 16 | 0 |
Motion passes. Hubert to coordinate with CWG.
强调我的。
看来,受约束的非模板化函数现在已从 C++20 中删除。
是否有限制非模板化方法的语法?我在带有 clang 概念分支和 gcc 的 godbolt 上尝试过的所有语法都无法编译:
// these examples do not compile
template <bool B>
struct X
{
requires B
void foo() {}
};
template <class T>
struct Y
{
requires (std::is_trivially_copyable_v<T>)
auto foo() {}
};
使其编译的技巧与您在 SFINAE 中需要做的技巧相同,即制作方法模板,即使它们实际上不是模板。有趣的是,约束似乎不需要方法模板,它可以单独在 class 模板上正常工作,所以我真的希望有一种方法可以通过概念应用约束,而不必求助于老技巧:
// old hacks
template <bool B>
struct X
{
template <bool = B>
requires B
auto foo() {}
};
template <class T>
struct Y
{
template <class = T>
requires std::is_trivially_copyable_v<T>
auto foo() {}
};
现实生活中的例子:
template <class T, bool Copyable_buf = false>
struct Buffer
{
/* ... */
requires Copyable_buf
Buffer(const Buffer& other) {}
/* ... */
};
template <class T>
using Copyable_buffer = Buffer<T, true>;
是的,有!! The requires clause 可以作为函数声明符的最后一个元素出现,在这种情况下它允许约束非模板方法(或与此相关的自由函数):
// This works as expected! Yey!!
template <class T, bool Copyable_buf = false>
struct Buffer
{
Buffer(const Buffer& other) requires Copyable_buf
{
// ...
}
};
template <bool B>
struct X
{
auto foo() requires B
{
// ...
}
};
template <class T>
struct Y
{
auto foo() requires std::is_trivially_copyable_v<T>
{
// ...
}
};
这个答案是经验性的,基于对当前概念实现的测试。 Godbolt test.
为了支持其他答案,这里是最新标准草案中关于此的规范性措辞:
[dcl.decl]
1 A declarator declares a single variable, function, or type, within a declaration. The init-declarator-list appearing in a declaration is a comma-separated sequence of declarators, each of which can have an initializer.
init-declarator-list: init-declarator init-declarator-list , init-declarator init-declarator: declarator initializeropt declarator requires-clause4 The optional requires-clause ([temp]) in an init-declarator or member-declarator shall not be present when the declarator does not declare a function ([dcl.fct]). When present after a declarator, the requires-clause is called the trailing requires-clause. The trailing requires-clause introduces the constraint-expression that results from interpreting its constraint-logical-or-expression as a constraint-expression. [ Example:
void f1(int a) requires true; // OK auto f2(int a) -> bool requires true; // OK auto f3(int a) requires true -> bool; // error: requires-clause precedes trailing-return-type void (*pf)() requires true; // error: constraint on a variable void g(int (*)() requires true); // error: constraint on a parameter-declaration auto* p = new void(*)(char) requires true; // error: not a function declaration
— end example ]
如这两段所述,尾随的 requires 子句可以出现在函数声明符的末尾。它的意思是通过它接受作为参数(包括概念)的常量表达式来约束函数。
最近有关于此的更改。参见 https://github.com/cplusplus/nbballot/issues/374
它指出:
How constraints work with non-templated functions is still under heavy construction during this late stage in the process. While we have provided various comments that build in a direction where supporting such constructs (including ordering between multiple constrained functions based on their constraints) would become possible, we acknowledge that WG 21 might not find a solution with consensus in time for the DIS. We ask WG 21 to evaluate the risk of shipping the feature in such a state and consider removing the ability to declare such functions.
Does EWG want to consider this for C++20?
| F | A | |----|----| | 16 | 0 |
Motion passes. Hubert to coordinate with CWG.
强调我的。
看来,受约束的非模板化函数现在已从 C++20 中删除。