c++ - 嵌入模板时模板化函数类型丢失

标签 c++ constraints c++20 c++-concepts

在研究 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/

相关文章:

c++ - 在 clang 和 gcc 中移动可分配的 lambda

c# - 验证列表中的 bool 方法(约束)

recursion - 是否可以在 SPARQL 中表达递归定义?

c++ - 指向指针的引用变量

C++ vector 问题

c++ - 三向比较运算符总是有效的吗?

c++ - 使用 C++ 20 概念检查函数是否返回 const 值

C++20 模板 lambda : how to specify template argument?

c++ - Qwt 重新缩放轴

constraints - DC/OS Marathon 约束主机名列表