簡體   English   中英

如何檢測過載解析失敗?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM