[英]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
。 不過,專業化列表需要相當長才能涵蓋所有const
、 volatile
、 noexcept
和 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.