在研究 C++20 的概念时,我发现在创建一个描述函数应该如何的概念时(即 T 必须是一个以 size_t
作为参数的可调用函数),然后使用该概念在另一个模板中,函数的类型似乎“丢失”了。我真的没有很好的表达方式,所以这是代码:
template<typename Func, typename ... Args>
concept FuncWithArgs = requires (Func f, Args... args) { f((size_t)1, args...); };
template<FuncWithArgs Func, typename ... Args>
void Foo(const Func& f, size_t i = 0, Args... args)
{
f(i, args...);
}
然后用以下方式调用它:
void MyFunc(size_t i, const std::string& s)
{
std::cout << i << ", " << s << std::endl;
}
int main(int argc, char **argv)
{
Foo(MyFunc, 1, "asdf");
return 0;
}
给出以下编译错误消息(使用 GCC 11.2 和 -std=c++20, https://godbolt.org/z/dvs9j77o3 ):
<source>: In function 'int main(int, char**)':
<source>:20:8: error: no matching function for call to 'Foo(void (&)(size_t, const string&), int, const char [5])'
20 | Foo(MyFunc, 1, "asdf");
| ~~~^~~~~~~~~~~~~~~~~~~
<source>:8:6: note: candidate: 'template<class Func, class ... Args> requires FuncWithArgs<Func> void Foo(const Func&, size_t, Args ...)'
8 | void Foo(const Func& f, size_t i = 0, Args... args)
| ^~~
<source>:8:6: note: template argument deduction/substitution failed:
<source>:8:6: note: constraints not satisfied
<source>: In substitution of 'template<class Func, class ... Args> requires FuncWithArgs<Func> void Foo(const Func&, size_t, Args ...) [with Func = void(long unsigned int, const std::__cxx11::basic_string<char>&); Args = {const char*}]':
<source>:20:8: required from here
<source>:5:9: required for the satisfaction of 'FuncWithArgs<Func>' [with Func = void()]
<source>:5:24: in requirements with 'Func f', 'Args ... args' [with Args = {}; Func = void()]
<source>:5:59: note: the required expression 'f((size_t)(1), args ...)' is invalid
5 | concept FuncWithArgs = requires (Func f, Args... args) { f((size_t)1, args...); };
| ~^~~~~~~~~~~~~~~~~~~~
cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
仔细观察,我首先看到 [with Func = void(long unsigned int, const std::__cxx11::basic_string<char>&); Args = {const char*}]
,紧接着是 [with Args = {}; Func = void()]
。为什么/怎么做 Func
改变?
经过更多挖掘,我想出了一个可行的解决方案( https://godbolt.org/z/j6W7P895q ):
template<typename Func, typename ... Args>
requires requires (Func f, Args... args)
{
f((size_t)1, args...);
}
void Foo(const Func& f, size_t i = 0, Args... args)
{
f(i, args...);
}
由于使用的约束与我尝试使用 concept
执行的约束相同,这让我相信函数的类型已“丢失”,并且概念本身已正确编写。
是我做得不对、是已知问题还是模板的限制?
最佳答案
当你写下这个:
template<typename Func, typename ... Args>
concept FuncWithArgs = requires (Func f, Args... args) { f((size_t)1, args...); };
template<FuncWithArgs Func, typename ... Args>
void Foo(const Func& f, size_t i = 0, Args... args)
{
f(i, args...);
}
Foo
的声明是这样的简写:
template <typename Func, typename ... Args>
requires FuncWithArgs<Func>
void Foo(const Func& f, size_t i = 0, Args... args)
{
f(i, args...);
}
这可能清楚地表明出了什么问题。您要求该函数可以在没有参数的情况下调用(实际上是 1 个参数,即 size_t
),但这不是您想要的。你想要这个:
template <typename Func, typename ... Args>
requires FuncWithArgs<Func, Args...>
void Foo(const Func& f, size_t i = 0, Args... args)
{
f(i, args...);
}
可以使用以下简写来编写:
template <typename ... Args, FuncWithArgs<Args...> Func>
void Foo(const Func& f, size_t i = 0, Args... args)
{
f(i, args...);
}
关于c++ - 嵌入模板时模板化函数类型丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70614651/