为什么std::invocable概念会阻止这段代码编译

5

我不明白为什么以下代码中,lambda表达式和函数都未被识别为 std::invocable 兼容类型:

#include <concepts>
#include <iostream>

void f( std::invocable auto callback)
{
    callback(47);
}

void function_callback(int i)
{
    std::cout << i << std::endl;
}

auto lambda_callback = [](int i )
{
    std::cout << i << std::endl;
};

int main(int) 
{
    f(&function_callback);
    f(lambda_callback);
}

我正在使用启用了-std=c++2a标志的GCC主干版本。


1
如果您遇到构建错误,请始终将其完整地复制并作为文本粘贴到问题本身中。并在出现错误的行上添加注释。 - Some programmer dude
1个回答

15

如果您查看invocable的定义(或在标准中):

template< class F, class... Args >
concept invocable =
  requires(F&& f, Args&&... args) {
    std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
      /* not required to be equality preserving */
  };

这意味着什么:

void f( std::invocable auto callback)

如果我们以长形式写出来,可能会更加清晰:

template <typename F>
    requires std::invocable<F>
void f(F callback);

这是否意味着F可以在没有参数的情况下被调用 - 即它是一个无参函数(Args...在此处为空)。您的函数和lambda都不是无参函数 - 它们都是一元函数,因此约束正确拒绝这些。

你可能想要的是:

void f( std::invocable<int> auto callback)

该函数检查callback函数是否可以接受一个类型为int的参数并进行调用。


我并不100%确定我已经理解了为什么 Args... 被认为是无参,而不是自动推断为 int,但是您提出的修复方法是有效的。 - nyarlathotep108
7
概念从来不是推导出来的,而是被明确定义的。 - Barry
有没有一种使用概念真正表示“任何”可调用类型的方法,而不需要回滚到模板语法? - nyarlathotep108
3
你会用那个信息做什么?你有一个模板,但是它被一些不确定的类型约束了 - 但你不知道具体是什么类型?从总体上来说,这个问题甚至无法得到回答。 - Barry
2
@nyarlathotep108: 记住:约束条件应该表达你希望如何使用一个东西。你不会用“任何”参数来调用它;你会用一些参数来调用它。因此,你的约束条件应该表达你对函数使用意图的意图。 - Nicol Bolas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接