Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
以lambda作为参数的约定 我正在编写一个C++应用程序,并在lambda参数上抽象了一个方法。我最初使用了以下签名: void atomically(void (*block)(T& value, bool& retry))_C++_Lambda - Fatal编程技术网

以lambda作为参数的约定 我正在编写一个C++应用程序,并在lambda参数上抽象了一个方法。我最初使用了以下签名: void atomically(void (*block)(T& value, bool& retry))

以lambda作为参数的约定 我正在编写一个C++应用程序,并在lambda参数上抽象了一个方法。我最初使用了以下签名: void atomically(void (*block)(T& value, bool& retry)),c++,lambda,C++,Lambda,但是我发现不能将任意lambda作为函数指针传递——lambda必须没有捕获。我可以用 void atomically(const std::function<void (T&, bool&)>& block) 但我发现这是不可接受的,因为它允许块按值而不是按引用获取其参数,这很容易出错,调试起来也很微妙 将lambda作为参数的正确约定是什么?或者,在最终的模板解决方案中,是否有办法确保块通过引用获取其参数?我认为您不应该将lambda作为参数调用,它们将

但是我发现不能将任意lambda作为函数指针传递——lambda必须没有捕获。我可以用

void atomically(const std::function<void (T&, bool&)>& block)
但我发现这是不可接受的,因为它允许
按值而不是按引用获取其参数,这很容易出错,调试起来也很微妙


将lambda作为参数的正确约定是什么?或者,在最终的模板解决方案中,是否有办法确保
通过引用获取其参数?

我认为您不应该将lambda作为参数调用,它们将生成值-而在这种情况下,您的函数在原子上期望函数作为参数,可能您可以使用std:function来描述函数原型,正如本文所述,您可以使用以下内容:

template <typename T>
using block = std::function<void(T&, bool&)>;
模板
使用block=std::function;

避免使用传递指针并能够通过引用传递

也许这是一种愚蠢的方式,但是。。。如果你能使用C++17。。。您可以尝试使用
std::function
演绎指南

我是说。。。您可以准备一个自定义类型特征来检查
std::function
是否属于请求的类型

template <typename>
struct checkFunc : public std::false_type
 { };

template <typename T>
struct checkFunc<std::function<void(T&, bool&)>> : public std::true_type
 { };
你可以核实一下

auto l1 = [](int &, bool &){};

atomically(l1);
编译,因为
l1
的类型将
F
作为
std::function
生成与
checkFunc
专门化匹配的类型,所以启用了
原子(l1)
,并且

auto l2 = [](int, bool &){};

atomically(l2);
不编译,因为
l2
的类型生成的
F
类型为
std::function
,与
checkFunc
专门化不匹配,因此
原子(l2)
未启用

一种可能的替代方法是
atomically()
表单,可能可读性稍差,但其优点是第二个模板参数无法解释,如下所示

template <typename L>
std::enable_if_t<checkFunc<decltype(std::function{std::declval<L>()})>::value> 
      atomically (L const & bl)
 { }
模板
std::如果启用,则启用
原子(L常量和bl)
{ }

注意,在这两种情况下,编译时都会使用
std::function
,以决定是否启用
原子()
,但在运行时不会创建
std::function
对象:lambda保持lambda并作为lambda运行。

您可能需要一些
function\u视图
(取自)(顾名思义,没有所有权,所以不要存储它):

模板
类功能视图;
模板
类函数\u视图最终
{
私人:
使用签名类型=TReturn(无效*,目标…);
无效*\u ptr;
TReturn(*已擦除)(无效*,目标;
公众:
模板>
函数_view(T&&x)noexcept:_ptr{(void*)std::addressof(x)}
{
_已擦除\u fn=[](无效*ptr,目标…xs)->t返回{
返回(*重新解释铸件(ptr))(
标准:正向(xs);
};
}
decltype(自动)运算符()(TArgs…xs)常量
noexcept(noexcept(_擦除的_fn(_ptr,std::forward(xs)…))
{
返回_擦除_fn(_ptr,std::forward(xs)…);
}
};
然后您可以使用:

void atomically(const function_view<void (T&, bool&)>& block)
void原子(常量函数视图和块)

如评论中所述,
T&
T
的一个子类型,因此你必须更聪明,但不要太糟糕。我们可以明确要求我们想要的东西,禁止我们不想要的东西:

template<class F>
void atomically(const F& block)
{
    static_assert(std::is_invocable_v<const F&, T&, bool&>, "wrong signature");
    static_assert(!std::is_invocable_v<const F&, T&&, bool&>, "need to mutate value");
    static_assert(!std::is_invocable_v<const F&, T&, bool&&>, "need to mutate retry");
}
模板
原子无效(常数F和块)
{
静态断言(std::is_invocable_v,“错误签名”);
静态断言(!std::is_invocable_v,“需要改变值”);
静态断言(!std::is_invocable_v,“需要变异重试”);
}

请参阅:

您可能需要一个“函数”类型特征。或者,您可以使用一些
函数_view
作为源代码,为什么
不复制其参数如此重要?您是否意识到您实际上无法强制执行它?因为,即使它通过引用获取其参数,它也可能在某个时候复制它们。@Acorn:OP想要禁止:
omically([](T&T,bool&b){/**})
并强制原子地拥有
([](T&T,bool&b){/**})
@luqui:注意,带有
的变量在原子上无效(const std::function&block)
也没有强制执行这一点。我完全不理解这一点。我想避免
std::function
,因为它在堆上分配–我不知道将其重命名为
block
有什么帮助。我想这个答案是误读问题的结果。很糟糕,但它确实发生了。@luqui是的,正如您的下的粗鲁评论中提到的那样评论,我误读了这一点,对此表示歉意。我无意冒犯你。我为冒犯你表示歉意。代替C++17的CTAD,你可以检查
std::function(bl)
是否格式正确(C++14)(因此
使用check\u type=std::is_constructurable的模板是可构造的
)。@Jarod42-我尝试过类似的东西(通过
decltype()
)但是没有成功…我将尝试
std::is_constructible
@Jarod42-失败:对于
std::is_constructible::value
我得到
true
,其中
l2
[](int,bool&){};
(根据OP要求,这是不可接受的)是的,它的格式确实很好:-/没有真正处理您的签名约束,因为
void foo(bool)
function\u view
(和
std::function
)是兼容的。确实,它没有完全处理我的约束,但在任何情况下都非常方便,谢谢
template <typename TSignature>
class function_view;

template <typename TReturn, typename... TArgs>
class function_view<TReturn(TArgs...)> final
{
private:
    using signature_type = TReturn(void*, TArgs...);

    void* _ptr;
    TReturn (*_erased_fn)(void*, TArgs...);

public:
    template <typename T, typename = std::enable_if_t<
                              std::is_callable<T&(TArgs...)>{} &&
                              !std::is_same<std::decay_t<T>, function_view>{}>>
    function_view(T&& x) noexcept : _ptr{(void*)std::addressof(x)}
    {
        _erased_fn = [](void* ptr, TArgs... xs) -> TReturn {
            return (*reinterpret_cast<std::add_pointer_t<T>>(ptr))(
                std::forward<TArgs>(xs)...);
        };
    }

    decltype(auto) operator()(TArgs... xs) const
        noexcept(noexcept(_erased_fn(_ptr, std::forward<TArgs>(xs)...)))
    {
        return _erased_fn(_ptr, std::forward<TArgs>(xs)...);
    }
};
void atomically(const function_view<void (T&, bool&)>& block)
template<class F>
void atomically(const F& block)
{
    static_assert(std::is_invocable_v<const F&, T&, bool&>, "wrong signature");
    static_assert(!std::is_invocable_v<const F&, T&&, bool&>, "need to mutate value");
    static_assert(!std::is_invocable_v<const F&, T&, bool&&>, "need to mutate retry");
}