I have this (supposedly not so useful) class template with templated constructor which is a candidate for perfect forwarding. I, however, wanted to make sure that the types passed to the constructor are the exact same as the ones specified for the whole class (without cvref qualifiers):
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";
}
};
Now I can make:
auto f = foo<int, int>(1, 1);
and I can't make:
auto f = foo<float, int>(1, 1);
which is good.
But I wanted to extract the requires ...
body to a 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
}
But this gives me this error:
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); |
I suppose I might be doing something wrong with the concept same_unqualified_types
where I'm trying to have two parameter packs. I've tried to test it manually, but it doesn't seem to work, even if I do same_unqualified_types<int, int>
or same_unqualified_types<int, int, Pack...>
, where Pack...
is a parameter pack of two int
s.
Where is my logic flawed? Can I extract that requires
clause to a concept
?
Disclaimer: I know I can achieve something similar with CTAD and deduction guides - without even needing any concepts. I just wish to know where my understanding is flawed.