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

时间:2017-07-19 12:23:16

标签: c++ c++11 templates variadic-templates typetraits

在尝试更好地理解可变参数模板时,我自己设定了基于给定条件编写编译时类型选择器的任务(从<type_traits>中定义的条件中选择,例如std::is_signed,{ {1}}等。选择器应该选择满足条件的第一种类型,并指定为模板参数。

举个例子:

std::is_floating_point

这些是我喜欢我的选择器的功能:

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

    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
    

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

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

    这会按预期选择类型,并符合要求1.现在我的问题:

    • 如何满足要求2 ,即如果有人尝试使用选择器而不向其传递类型,则会生成用户友好的编译错误?
    • 有更好的方法吗(仅使用标准库功能)?

    奖金问题,如果有人愿意详细说明:

    • 这是否符合模板元编程的要求?

1 个答案:

答案 0 :(得分:3)

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

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

所以first_if_any<Cond>会产生类似于:

的消息
  

错误:类模板的模板参数太少&#39; first_if_any&#39;

然后,您当前实现的问题在于您使用了您想要禁止的内容,我的意思是first_if_any<Cond>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;
};