![](/img/trans.png)
[英]Lambda expression in C++17: trailing return type vs static_cast for type conversion
[英]C++17 Infer return type of lambda based visitor
這是https://en.cppreference.com/w/cpp/utility/variant/visit 中給出的基於 lambda 重載的訪問者:
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
std::visit(overloaded {
[](auto arg) { std::cout << arg << ' '; },
[](double arg) { std::cout << std::fixed << arg << ' '; },
[](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}, v);
其中v
是一個variant
,它的所有類型都必須實現 lambdas。
我想向overloaded
添加一個函數,該函數具有與所有 lambdas 相同的返回類型(然后是visit(overloaded{...}, v)
的返回類型)。 類似於:
template<class... Ts> struct overloaded : Ts...
{
using Ts::operator()...;
common_type_t<decltype(declval<Ts>())...> test() const { return {}; }
};
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
auto r = std::visit(overloaded {
[](auto arg) { return 1; },
[](double arg) { return 2; },
[](const std::string& arg) { return 3; },
}, v);
這里出了點問題,並且common_type<_Tp...>::type
不存在。 我想過使用common_type_t<invoke_result_t<Ts>...>
但我沒有 lambdas 的參數,所以invoke_result<Ts..>>::type
在那里失敗。
我錯過了什么?
這個問題沒有通用的解決方案,因為如果 lambdas 之一是通用的,例如
[](auto arg) { return arg; }
那么沒有std::variant
對象就無法推導出返回類型。
但是,我們可以嘗試從具有非模板operator()
那些 lambda 表達式中推斷出常見類型。 這種特殊情況的解決方案如下。
首先創建一個推導 lambda 返回類型的特征,如果推導失敗則返回empty
:
struct empty {};
template<typename Ret, typename Fn, typename Arg>
Ret return_type(Ret(Fn::*)(Arg));
template<typename Ret, typename Fn, typename Arg>
Ret return_type(Ret(Fn::*)(Arg) const);
template<typename Fn>
auto return_type(Fn) -> decltype(return_type(&Fn::operator()));
empty return_type(...);
然后調整std::common_type
:
template<>
struct std::common_type<empty, empty> {
using type = empty;
};
template<typename T>
struct std::common_type<T, empty> {
using type = T;
};
template<typename T>
struct std::common_type<empty, T> {
using type = T;
};
最后把所有這些放在一起:
template<class... Ts> struct overloaded : Ts... {
using Ts::operator()...;
static auto test() ->
std::common_type_t<decltype(return_type(std::declval<Ts>()))...>;
};
例子:
auto fn = overloaded {
[](auto arg) { },
[](int arg) { return 0; },
[](std::string) { return 1.; }
};
static_assert(std::is_same_v<decltype(fn.test()), double>);
如果無法推導出類型,則test()
的返回類型將為empty
:
auto fn = overloaded {
[](auto arg) { }
};
static_assert(std::is_same_v<decltype(fn.test()), empty>);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.