[英]How to detect overload resolution failure?
考慮以下代碼片段:
#include <tuple>
#include <type_traits>
#include <utility>
#include <cstddef>
template <typename ...>
struct always_false : std::false_type {};
template <>
struct always_false<decltype([] {})> : std::true_type {};
template <typename ...Ts>
inline constexpr bool always_false_v = always_false<Ts...>::value;
template <typename>
struct type_wrapper {};
template <std::size_t I, typename T>
struct tuple_index_impl_base
{
auto foo(type_wrapper<T>) -> std::integral_constant<std::size_t, I>;
};
template <typename ...Ts>
struct tuple_index_impl_base_fallback
{
auto foo(...)
{
static_assert(always_false_v<Ts...>, "Type not exist.");
}
};
template <typename, typename ...>
struct tuple_index_impl;
template <std::size_t ...Is, typename ...Ts>
struct tuple_index_impl<std::index_sequence<Is...>, Ts...> : tuple_index_impl_base<Is, Ts>..., tuple_index_impl_base_fallback<Ts...>
{
using tuple_index_impl_base<Is, Ts>::foo...;
using tuple_index_impl_base_fallback<Ts...>::foo;
};
template <typename, typename>
struct tuple_index;
template <typename T, typename ...Ts>
struct tuple_index<T, std::tuple<Ts...>> : decltype(std::declval<tuple_index_impl<std::make_index_sequence<std::tuple_size_v<std::tuple<Ts...>>>, Ts...>>().foo(std::declval<type_wrapper<T>>())) {};
template <typename T, typename U>
inline constexpr std::size_t tuple_index_v = tuple_index<T, U>::value;
它實現了元函數tuple_index
以獲取與std::tuple
中的類型對應的索引。
如果類型存在並且在元組中只存在一次,它就可以正常工作:
constexpr std::size_t i = tuple_index_v<char&, std::tuple<int, float, char, char&, const char*, char>>; // i == 3
如果類型不存在,將觸發static_assert
並打印一條錯誤消息:
constexpr std::size_t i = tuple_index_v<long, std::tuple<int, float, char, char&, const char*, char>>; // error C2338: static_assert failed: 'Type not exist.'
(現場演示)
但是,如果該類型存在不止一次,編譯器不會打印用戶友好的錯誤消息,而是會啟動ambiguous call to overloaded function
:
constexpr std::size_t i = tuple_index_v<char, std::tuple<int, float, char, char&, const char*, char>>; // error C2668: 'tuple_index_impl_base_fallback<int,float,char,char &,const char *,char>::foo': ambiguous call to overloaded function
(現場演示)
似乎如果重載集中有兩個相同的函數,編譯器將不會選擇后備 function(本例中為tuple_index_impl_base_fallback<Ts...>::foo(...)
)。
在這種情況下如何檢測重載解析失敗並使用static_assert
捕獲它?
您可以使用requires
表達式檢查重載決議是否成功:
template <std::size_t ...Is, typename ...Ts>
struct tuple_index_impl<std::index_sequence<Is...>, Ts...> : tuple_index_impl_base<Is, Ts>..., tuple_index_impl_base_fallback<Ts...>
{
using tuple_index_impl_base<Is, Ts>::foo...;
using tuple_index_impl_base_fallback<Ts...>::foo;
template<typename T>
static auto foo2() {
using wrapper = type_wrapper<T>;
static_assert(requires(tuple_index_impl i, wrapper w) { i.foo(w); }, "Duplicate type");
return tuple_index_impl{}.foo(wrapper{});
}
};
template <typename T, typename ...Ts>
struct tuple_index<T, std::tuple<Ts...>> : decltype(tuple_index_impl<std::make_index_sequence<std::tuple_size_v<std::tuple<Ts...>>>, Ts...>::template foo2<T>()) {};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.