c++ - 使用默认参数从 lambda 调用最少数量的参数

标签 c++ c++14 variadic-templates template-meta-programming default-arguments

就我目前正在编写的库而言,我的目标是,在给定用户指定的 lambda 函数的情况下,使用我选择的参数在内部调用它。

到目前为止它工作正常,看起来像这样:

#include <tuple>

template<typename T> struct GetFinfos;

template<typename R, typename F, typename ...Args>
struct GetFinfos<R(F::*)(Args...) const> {
    static std::tuple<Args...> createChosenTuple() {
        return std::make_tuple(Args(1)...);
    }   
};

template<typename F>
void internal_lambda_call(const F & f) {
//let's suppose for convenience that we have a working call_from_tuple in C++14
    std::apply(f,  GetFinfos<decltype(&F::operator())>::createChosenTuple() );
}

int main()
{
    auto f = [](int i, int j, int k) { };

    internal_lambda_call(f); // calls f(1,1,1);
}

现在,C++14 引入了带有默认参数的 lambda 函数,我想知道库是否可以使用来自用户的这些额外信息。

auto g = [](int i, int j = 5, int k = 5) { };

据我了解,具有默认参数的 lambda 仍然只有一个 ClosureType::operator ret(*)(params)() 运算符。因此 GetFinfos 对默认参数视而不见,internal_lambda_call(g) 调用 g(1,1,1)

但是,由于我们可以访问完整的参数类型列表,理论上我们可以尝试使用减少数量的参数调用 lambda 并选择最后一个有效的参数。

g(1,1,1)  //valid call
g(1,1)    //valid call
g(1);     //valid call   <---- last valid one 
g();      //invalid call

所以我的问题是:如果有任何现有机制,那么 internal_lambda_call(g) 会自动调用 g(1)g(1,5, 5)?我看到 here通用 lambda 可用于包装 lambda 并使其使用明确数量的参数。但我没有找到一种方法来自动获取最少数量的参数。

最佳答案

I don't see a way to get this minimal number of argument automatically.

也许……用一点递归和 SFINAE……

#include <tuple>
#include <utility>

template <typename F, typename T, std::size_t ... Is>
constexpr auto gmna_helper (std::index_sequence<Is...> is, int)
   -> decltype( (void)std::declval<F>()
                   (std::declval<std::tuple_element_t<Is, T>>()...),
                std::size_t{} )
 { return sizeof...(Is); }

template <typename F, typename T, std::size_t ... Is>
constexpr auto gmna_helper (std::index_sequence<Is...>, long)
 { return gmna_helper<F, T>(std::make_index_sequence<sizeof...(Is)+1u>{}, 0); }

template <typename F, typename ... Ts>
constexpr std::size_t getMinNumArgs ()
 { return gmna_helper<F, std::tuple<Ts...>>(std::index_sequence<>{}, 0); }

int main ()
 {
   auto g = [](int, int = 5, int = 5) { };

   constexpr auto n = getMinNumArgs<decltype(g), int, int, int>();

   static_assert( n == 1, "!" );
 }

正如同一 OP 在评论中所说,两个 gmna_helper() 之间的签名差异,intlong参数,是为了引入一个顺序:该函数是用 int 调用的,因此在可用时选择恰好接收 int 的版本。即:当类型为 F 的函数仅可使用第一个 sizeof...(Is) 参数调用时被选中。

否则,当 int 版本不可用时(SFINAE 因 decltype() 内的调用失败而被禁用)long(永远可用)被选中。

关于c++ - 使用默认参数从 lambda 调用最少数量的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57253645/

相关文章:

c++ - C++ 中枚举的获取和设置

c++ - 如何以用户身份在 Windows (Linux TCP_INFO) 上获取 TCP RTT

C++ 绑定(bind)返回类型模板参数

c++ - 数组新表达式中的直接初始化与列表初始化

c++ - 'std::thread' 的初始化没有匹配的构造函数

c++ - 如何更改参数包中的最后一个参数?

c++ - 将二进制节点类转换为非终端类

c++ - 参数包必须在参数列表的末尾......何时以及为什么?

c++ - 来自可变参数模板的固定数量的模板参数

c++ - 值得产生一个新线程的最小工作量