簡體   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