如何将带有两个参数包的 requires 子句提取到一个概念中?
How to extract requires clause with two parameter packs into a concept?
我有这个(据说不太有用)class 模板,它带有模板化构造函数,是完美转发的候选者。但是,我想确保传递给构造函数的类型与为整个 class (没有 cvref 限定符)指定的类型完全相同:
template <typename... Ts>
struct foo {
template <typename... CTs>
requires (std::same_as<std::remove_cvref_t<Ts>, std::remove_cvref_t<CTs>> && ...)
foo(CTs&& ...) {
std::cout << "called with " << (sizeof...(CTs)) << " args\n";
}
};
现在我可以做:
auto f = foo<int, int>(1, 1);
我做不到:
auto f = foo<float, int>(1, 1);
哪个好
但我想将 requires ...
正文提取到 concept
:
template <typename... T1s, typename... T2s>
concept same_unqualified_types = (
std::same_as<
std::remove_cvref_t<T1s>,
std::remove_cvref_t<T2s>
> && ...
);
template <typename... Ts>
struct foo {
template <typename... CTs>
requires same_unqualified_types<Ts..., CTs...>
foo(CTs&& ...) { // 16
std::cout << "called with " << (sizeof...(CTs)) << " args\n";
}
};
int main() {
auto f = foo<int, int>(1, 1); // 22
}
但这给了我这个错误:
main.cpp: In function 'int main()':
main.cpp:22:32: error: no matching function for call to 'foo<int, int>::foo(int, int)'
22 | auto f = foo<int, int>(1, 1);
|
main.cpp:16:5: note: candidate: 'template<class ... CTs> requires same_unqualified_types<Ts ..., CTs ...> foo<Ts>::foo(CTs&& ...) [with CTs = {CTs ...}; Ts = {int, int}]'
16 | foo(CTs&& ...) {
| ^~~
main.cpp:16:5: note: template argument deduction/substitution failed:
main.cpp:16:5: note: constraints not satisfied
main.cpp: In substitution of 'template<class ... CTs> requires same_unqualified_types<Ts ..., CTs ...> foo<int, int>::foo(CTs&& ...) [with CTs = {int, int}]':
main.cpp:22:32: required from here
main.cpp:5:9: required for the satisfaction of 'same_unqualified_types<Ts ..., CTs ...>' [with CTs = {int, int}; Ts = {int, int}]
main.cpp:22:32: error: mismatched argument pack lengths while expanding 'same_as<typename std::remove_cvref<T1s>::type, typename std::remove_cvref<T2s>::type>'
22 | auto f = foo<int, int>(1, 1);
|
我想我尝试使用两个参数包的 concept same_unqualified_types
可能做错了什么。我尝试手动测试它,但它似乎不起作用,即使我做 same_unqualified_types<int, int>
或 same_unqualified_types<int, int, Pack...>
,其中 Pack...
是两个 [=21= 的参数包]s.
我的逻辑哪里有问题?我可以将 requires
子句提取到 concept
吗?
免责声明:我知道我可以通过 CTAD 和演绎指南实现类似的目标——甚至不需要任何概念。我只是想知道我的理解哪里有问题。
概念在模板参数包方面没有特殊权限。你不能在一组模板参数中有两个包,除非有一些东西可以根据传递给它们的参数来区分它们(一个可以是一系列类型,而另一个是一系列值,或者你可以访问模板参数推导来区分它们,或类似的东西)。
你能做的最好的事情就是创建一个不合格的 same_as
等价物,并根据需要将其与包扩展一起使用:
template<typename T, typename U>
concept same_as_unqual = std::same_as<<std::remove_cvref_t<T>, <std::remove_cvref_t<U>>;
template <typename... Ts>
struct foo {
template <typename... CTs>
requires (same_as_unqual<Ts, CTs> && ...)
...
在参数之间进行成对比较的单一概念是不可能的。好吧,这是可能的,但它会 冗长 很多,因为您可能需要将它们捆绑在某种类型列表中。我不认为 same_as_all<type_list<Ts...>, type_list<Us...>>
比显式扩展更好。
我有这个(据说不太有用)class 模板,它带有模板化构造函数,是完美转发的候选者。但是,我想确保传递给构造函数的类型与为整个 class (没有 cvref 限定符)指定的类型完全相同:
template <typename... Ts>
struct foo {
template <typename... CTs>
requires (std::same_as<std::remove_cvref_t<Ts>, std::remove_cvref_t<CTs>> && ...)
foo(CTs&& ...) {
std::cout << "called with " << (sizeof...(CTs)) << " args\n";
}
};
现在我可以做:
auto f = foo<int, int>(1, 1);
我做不到:
auto f = foo<float, int>(1, 1);
哪个好
但我想将 requires ...
正文提取到 concept
:
template <typename... T1s, typename... T2s>
concept same_unqualified_types = (
std::same_as<
std::remove_cvref_t<T1s>,
std::remove_cvref_t<T2s>
> && ...
);
template <typename... Ts>
struct foo {
template <typename... CTs>
requires same_unqualified_types<Ts..., CTs...>
foo(CTs&& ...) { // 16
std::cout << "called with " << (sizeof...(CTs)) << " args\n";
}
};
int main() {
auto f = foo<int, int>(1, 1); // 22
}
但这给了我这个错误:
main.cpp: In function 'int main()': main.cpp:22:32: error: no matching function for call to 'foo<int, int>::foo(int, int)' 22 | auto f = foo<int, int>(1, 1); | main.cpp:16:5: note: candidate: 'template<class ... CTs> requires same_unqualified_types<Ts ..., CTs ...> foo<Ts>::foo(CTs&& ...) [with CTs = {CTs ...}; Ts = {int, int}]' 16 | foo(CTs&& ...) { | ^~~ main.cpp:16:5: note: template argument deduction/substitution failed: main.cpp:16:5: note: constraints not satisfied main.cpp: In substitution of 'template<class ... CTs> requires same_unqualified_types<Ts ..., CTs ...> foo<int, int>::foo(CTs&& ...) [with CTs = {int, int}]': main.cpp:22:32: required from here main.cpp:5:9: required for the satisfaction of 'same_unqualified_types<Ts ..., CTs ...>' [with CTs = {int, int}; Ts = {int, int}] main.cpp:22:32: error: mismatched argument pack lengths while expanding 'same_as<typename std::remove_cvref<T1s>::type, typename std::remove_cvref<T2s>::type>' 22 | auto f = foo<int, int>(1, 1); |
我想我尝试使用两个参数包的 concept same_unqualified_types
可能做错了什么。我尝试手动测试它,但它似乎不起作用,即使我做 same_unqualified_types<int, int>
或 same_unqualified_types<int, int, Pack...>
,其中 Pack...
是两个 [=21= 的参数包]s.
我的逻辑哪里有问题?我可以将 requires
子句提取到 concept
吗?
免责声明:我知道我可以通过 CTAD 和演绎指南实现类似的目标——甚至不需要任何概念。我只是想知道我的理解哪里有问题。
概念在模板参数包方面没有特殊权限。你不能在一组模板参数中有两个包,除非有一些东西可以根据传递给它们的参数来区分它们(一个可以是一系列类型,而另一个是一系列值,或者你可以访问模板参数推导来区分它们,或类似的东西)。
你能做的最好的事情就是创建一个不合格的 same_as
等价物,并根据需要将其与包扩展一起使用:
template<typename T, typename U>
concept same_as_unqual = std::same_as<<std::remove_cvref_t<T>, <std::remove_cvref_t<U>>;
template <typename... Ts>
struct foo {
template <typename... CTs>
requires (same_as_unqual<Ts, CTs> && ...)
...
在参数之间进行成对比较的单一概念是不可能的。好吧,这是可能的,但它会 冗长 很多,因为您可能需要将它们捆绑在某种类型列表中。我不认为 same_as_all<type_list<Ts...>, type_list<Us...>>
比显式扩展更好。