c++ 演绎向导无法演绎lambda和函数类型

ikfrs5lh  于 2023-04-01  发布在  其他
关注(0)|答案(1)|浏览(126)

我正在用C++测试一个 Package 器对象,这是我的基本代码:

template <class res_type, class finisher_type, finisher_type finisher>
struct wrapper
{
    wrapper(res_type r, finisher_type) noexcept
    {
        item = r;
    }
    wrapper(res_type r) noexcept
    {
        item = r;
    }
    
    ~wrapper() noexcept
    {
        finisher(item);
    }

private:
    res_type item;
};

template <class func, func lambda = func()>
explicit wrapper(int, func)->wrapper<int, func, lambda>;

void test()
{
    int x = 0, y = 0;

    wrapper file{ x, [](int h) {if (h != -1 && h) close_resource(h); } };

    // void some_closer_function(int) {...}
    wrapper proc{ y, some_closer_function };
}

我面临两个问题。首先,在lambda捕获子句中放入任何内容都会使编译器抱怨'wrapper<int,func,lambda> wrapper(int,func)': could not deduce template argument for 'lambda'。这是因为带有捕获的lambda不能使用+转换为函数指针吗?
第二,使用some_closer_function的行编译,但由于演绎指南中的func lambda = func()lambdanullptr。我认为这是因为演绎指南中的func是函数指针,而不是函数类型本身。有没有办法强制它成为函数本身而不是函数指针,而不显式输入decltype(some_closer_function)
编辑3/25/2023
我创建了一个派生类来保存一个lambda,但这次是一个捕获类,因为我之前的代码可以保存一个无捕获的lambda。新的派生类通过保存一个指向lambda的指针,然后通过该指针调用它来实现这一点。

template <class res_type, class finisher_type, finisher_type finisher = finisher_type()>
struct wrapper
{
    wrapper(res_type r, finisher_type) noexcept
    {
        item = r;
    }
    wrapper(res_type r) noexcept
    {
        item = r;
    }

    ~wrapper() noexcept
    {
        if constexpr (!std::is_same_v<finisher_type, std::nullptr_t>)
            finisher(item);
    }

protected:
    res_type item;
};

template <class res_type, class lambda_type>
struct custom_wrapper : wrapper<res_type, std::nullptr_t>
{
    custom_wrapper(res_type item, lambda_type const& lambda) : base(item)
    {
        this->lambda = &lambda;
    }

    ~custom_wrapper()
    {
        lambda->operator()(base::item);
    }

private:
    using base = wrapper<res_type, std::nullptr_t>;
    const lambda_type* lambda;
};

void test()
{
    int x, y;

    custom_wrapper wrapper{ 234, [&](int) {} };

    return;
}

虽然这确实使一切工作,但这是未定义的行为吗?我问这个问题是因为我相信捕获lambda是包含捕获的class。在这种情况下,lambda对象是临时对象吗?就像在custom_wrapper wrapper{ 234, [&](int) {} };行中一样,并在custom_wrapper完成创建时被销毁?当custom_wrapper被销毁时,它最终会调用一个被销毁的lambda吗

6ojccjat

6ojccjat1#

函数形参 values 不参与模板实参推导。即使是类模板实参推导。非类型模板形参的模板形参不能推导。该形参的类型可以推导(template<auto value>是一个东西),但不能将其初始化为对象。
因此,如果要使用非类型模板参数,则必须由模板参数列表显式提供。
算是吧
如果你将一个值绑定到某个其他类的NTTP中,那么你可以将该类的一个示例作为参数传递,并让模板参数演绎来处理它。例如:

template<int I>
void func(std::integral_constant<int, I> ic);

func(std::integral_constant<int, 5>{});

你可以在这里做基本相同的事情,只是使用一个对NTTP有效的类用途:

template<auto Value>
struct compile_constant
{
  using type = decltype(Value);
  static inline constexpr type value = Value;
};

然后,您可以在类的构造函数中使用它,并使用适当的演绎指南来整理细节:

template <class res_type, class finisher_type, finisher_type finisher>
struct wrapper
{
    wrapper(res_type r, compile_constant<finisher_type, finisher>) noexcept
    {
        item = r;
    }
    wrapper(res_type r) noexcept
    {
        item = r;
    }
    
    ~wrapper() noexcept
    {
        finisher.value(item);
    }

private:
    res_type item;
};

template<typename res_type, auto Value>
wrapper(res_type, compile_constant<Value>) -> wrapper<res_type, typename compile_constant<Value>::type, compile_constant<Value>::value>;

当然,这意味着任何可调用对象都必须捆绑到compile_constant<callable>{}表达式中,但这就是试图将编译时常量偷偷带入函数参数的代价。
Here's a working example.

相关问题