繁体   English   中英

是否可以使用所有 arguments 默认构造调用 function?

[英]Is it possible to call a function with all arguments default constructed?

是否有可能像std::invoke那样有一个 function,但是这个 function 使用默认构造类型自动调用给定 function 的所有 arguments?

#include <iostream>
#include <functional>
// e.g. for a single arg 
struct Test{
    void operator()(int i) {
        std::cout << std::to_string(i) << "\n";
    }
};

int main(){
  Test test;
  std::invoke(test, {});  // this doesn't work, would like it to call with default constructed int (0).
  return 0;
} 

我想要类似的东西

int main()
{
  Test test;
  invoke_with_defaults(test); // prints 0
  return 0;
}

您需要一个带有模板化转换operator的 class,为任何类型返回{}

struct DefaultConstruct
{
    DefaultConstruct() = default;
    DefaultConstruct(const DefaultConstruct &) = delete;
    DefaultConstruct &operator=(const DefaultConstruct &) = delete;
    template <typename T> operator T() && {return {};}
};

int main()
{
    Test test;
    std::invoke(test, DefaultConstruct{});
} 

然后可以编写一个模板来自动确定其中有多少必须通过:

template <typename F, typename ...P>
decltype(auto) InvokeDefault(F &&func)
{
    if constexpr (std::is_invocable_v<F, P...>)
        return std::invoke(std::forward<F>(func), P{}...);
    else
        return InvokeDefault<F, P..., DefaultConstruct>(std::forward<F>(func));
}

int main()
{
    Test test;
    InvokeDefault(test);
} 

如果参数根本不可调用,则在超过某个实现定义的限制后会出现编译错误(在 Clang 上我达到了 256)。

由于语言限制,像{}这样的初始化列表无法作为参数转发。

但是您可以通过将其包装到可以传递的 Defaulter Defaulter中来模仿{}

#include <iostream>
#include <functional>
// e.g. for a single arg 
struct Test{
    void operator()(int i) {
        std::cout << std::to_string(i) << "\n";
    }
};

struct Defaulter{

    template<typename T>
    operator T(){
        return {};
    }
};

int main(){
  Test test;
  std::invoke(test, Defaulter{}); 
  return 0;
} 

您可以使用类似这样的方法来创建所有参数类型的元组,然后将其默认构造的实例传递给std::apply 不过,专业化列表需要相当长才能涵盖所有constvolatilenoexcept和 ref 限定的变体,当然它不能与模板或重载函数一起使用。

例如

template <typename T>
struct arg_extractor : arg_extractor<decltype(&T::operator())> {
};

template <typename R, typename... Args>
struct arg_extractor<R (*)(Args...)> {
    using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...)> {
    using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...) const> {
    using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...) noexcept> {
    using type = std::tuple<R, Args...>;
};
template <typename R, typename C, typename... Args>
struct arg_extractor<R (C::*)(Args...) const noexcept> {
    using type = std::tuple<R, Args...>;
};
// All the rest...

template <typename T>
using arg_extractor_t = typename arg_extractor<T>::type;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM