代码之家  ›  专栏  ›  技术社区  ›  themiurge

基于条件的编译时类型选择的可变模板

  •  1
  • themiurge  · 技术社区  · 7 年前

    为了更好地理解可变模板,我为自己设定了一项任务,即根据给定的条件(从中定义的条件中选择)编写编译时类型选择器 <type_traits> std::is_signed , std::is_floating_point 等等)。选择器应该从指定为模板参数的类型中选择第一个满足条件的类型。

    举个例子:

    template<template<typename> class Cond, typename... T> 
    struct first_if_any {
        // some code here
    };
    
    first_if_any<std::is_signed, unsigned, long, int>::type a; // long
    first_if_any<std::is_unsigned, short, unsigned long, unsigned>::type b; // unsigned long
    first_if_any<std::is_floating_point, int, float, double>::type c; // float
    

    以下是我希望选择器具备的功能:

    1. 如果没有满足条件的类型,请选择第一种类型
    2. 如果未指定类型,则打印用户友好的编译错误

    first_if_any<std::is_unsigned, long, int>::type a; // long
    first_if_any<std::is_arithmetic>::type b; // ERROR
    

    下面是我的想法(参见工作示例 here ):

    template<template<typename> class Cond, typename... T> 
    struct first_if_any {
        using type = void;
        static constexpr bool found = false;
    };
    
    template<template<typename> class Cond, typename First, typename... T> 
    struct first_if_any<Cond, First, T...> {
        using type = typename std::conditional<Cond<First>::value || !first_if_any<Cond, T...>::found, First, typename first_if_any<Cond, T...>::type>::type;
        static constexpr bool found = Cond<First>::value || first_if_any<Cond, T...>::found;
    };
    

    这将按预期选择类型,并满足要求1。现在回答我的问题:

    • 我如何满足要求2
    • 有更好的方法吗 (仅使用标准库功能)?

    1 回复  |  直到 7 年前
        1
  •  3
  •   Jarod42    7 年前

    要获得好的错误消息,您必须将声明更改为

    template<template<typename> class Cond, typename T, typename... Ts>
    struct first_if_any;
    

    所以 first_if_any<Cond>

    错误:类模板“first\u if\u any”的模板参数太少

    然后,您当前实现的问题是,您使用了您想要禁止的内容,我的意思是 (带有各种 first_if_any<Cond, T...> 哪里 T...

    您可以使用更容易处理默认类型的中间类:

    template<template<typename> class Cond, typename Default, typename... Ts>
    struct first_if_any_or_default;
    
    template<template<typename> class Cond, typename Default>
    struct first_if_any_or_default<Cond, Default>
    {
        using type = Default;
        static constexpr bool found = false;
    };
    
    template<template<typename> class Cond, typename Default, typename T, typename... Ts>
    struct first_if_any_or_default<Cond, Default, T, Ts...>
    {
    private:
        using next = first_if_any_or_default<Cond, Default, Ts...>;
    public:
        using type = typename std::conditional<Cond<T>::value,
                                               T,
                                               typename next::type>::type;
        static constexpr bool found = Cond<T>::value || next::found;
    };
    
    template<template<typename> class Cond, typename First, typename... Ts> 
    struct first_if_any {
    private:
        using helper = first_if_any_or_default<Cond, First, First, Ts...>;
    public:
        using type = typename helper::type;
        static constexpr bool found = helper::found;
    };