c++ 对于给定的模板类型,从可变模板中可用的类型列表中查找其精确匹配或最适合的类型以将其转换为

ncecgwcz  于 2023-04-01  发布在  其他
关注(0)|答案(2)|浏览(87)

我试图实现一个模板,将有以下定义

template<typename TypeToConvert, typename ... ListOfAvailableTypes>
struct best_match{...}

并且将屈服于提供2个成员的类型

1. value_type typedef - that is either exact match of TypeToConvert, if TypeToConvert was listed in ListOfAvailableTypes pack, or is the best suited type to convert TypeToConvert to, from the list of types available in ListOfAvailableTypes 
2. int index - that will contain the position of the found type in ListOfAvailableTypes pack

举个小例子

best_match<const char[4], std::string, int, void const*>

应屈服于提供少于2个成员的类型

best_match<const char[4], std::string, int, void const*>::value_type = void const*
best_match<const char[4], std::string, void const*>::index = 2

如果我想找到精确匹配或可转换匹配,我可以实现这一点,但我如何才能找到最适合的可转换类型呢?

hrirmatl

hrirmatl1#

您可以利用重载解析。可能有比这更短的实现

template<size_t I, typename T>
struct tester
{
    static T type(T);
    static std::integral_constant<size_t, I> index(T);
};

template<typename...>
struct overloader;

template<size_t... Is, typename... Ts>
struct overloader<std::index_sequence<Is...>, Ts...>
    : tester<Is, Ts>...
{
    using tester<Is, Ts>::type...;
    using tester<Is, Ts>::index...;
};

template<typename T, typename... Ts>
struct best_match
{
    using overloader = overloader<std::index_sequence_for<Ts...>, Ts...>;
    using value_type = decltype(overloader::type(std::declval<T>()));
    static constexpr auto index
        = decltype(overloader::index(std::declval<T>()))::value;
};
laik7k3q

laik7k3q2#

如何使用C++20

#include <type_traits>
#include <tuple>

template<typename TypeToConvert, typename... ListOfAvailableTypes>
struct best_match
{
    static_assert(sizeof...(ListOfAvailableTypes) > 0, "ListOfAvailableTypes must not be empty");

    static constexpr auto find_best_match() noexcept
    {
        constexpr auto update_best_match = [](auto best) constexpr noexcept {
            return [i = 0, &best](auto&& candidate) mutable constexpr -> decltype(auto) 
            {
                if constexpr (std::is_convertible_v<decltype(candidate), TypeToConvert> &&
                    (!std::is_same_v<TypeToConvert, decltype(candidate)>) &&
                    (!std::is_same_v<decltype(best), void> || 
                        !std::is_convertible_v<decltype(candidate), void>)) 
                {
                    if constexpr (std::is_same_v<decltype(best), void> ||
                        std::is_convertible_v<decltype(candidate), decltype(best)>)
                    {
                        return decltype(candidate){std::forward<decltype(candidate)>(candidate), i};
                    }
                }
                return std::move(best);
            };
        };

        return std::apply([&](auto&&... args) constexpr noexcept 
            {
            return (update_best_match(void{})(
                decltype(args){std::forward<decltype(args)>(args), 0}), ...);
            }
        , std::tuple_cat(std::tuple<ListOfAvailableTypes...>{}, std::tuple<>{}));
    }

    using value_type = typename decltype(find_best_match())::value_type;
    static constexpr int index = decltype(find_best_match())::index;
};

相关问题