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

通过类型别名从构造函数转发模板推导

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

    我有一个 Employee 使用两个成员函数(即数组)初始化。一个数组存储 雇员 已经和其他商店换班了 雇员 正在覆盖。我想定义一个helper类,允许我使用for range循环( for (:) )在任一阵列上。例如,如果我这样做:

    for (auto& ts : employee_freetime_iterator{ employee })
    

    for (auto& ts : employee_shift_iterator{ employee })
    

    它将迭代变换。我有一个类的定义如下:

    template <typename T,
        typename = std::enable_if_t<std::is_same_v<Employee, std::remove_cv_t<T>>>
    >
    struct employee_shift_iterator { 
        employee_shift_iterator(T& e);
    };
    

    在宣言中, T 要么是一个 或者一个 const Employee employee_freetime_iterator 一个给我 employee_shift_iterator . 为了减少代码冗余,我选择这样做:

    enum ScheduleType {
        FREE,
        SHIFT,
        ST_TOTAL
    };
    
    template <typename T, ScheduleType ST,
        typename = std::enable_if_t<std::is_same_v<Employee, std::remove_cv_t<T>>>
    >
    struct employee_iterator {
        constexpr static ScheduleType mScheduleType = ST;
    
        employee_iterator(T& e);
    };
    

    ScheduleType 选择不同的助手函数,让我在 雇员 计划类型 )像这样:

    template <typename T>
    using employee_freetime_iterator = employee_iterator<T, FREE>;
    
    template <typename T, typename SFINAE>
    using employee_shift_iterator = employee_iterator<T, SHIFT>;
    

    是否自动推断模板参数?按原样编译会产生以下错误:

    src/main.cpp:47:40: error: missing template arguments before ‘{’ token
      auto test = employee_freetime_iterator{ em };
    

    其中em是我先前在代码中创建的雇员。我已经重构了代码,删除了不必要的部分,并将其粘贴到下面。

    enum ScheduleType {
        FREE,
        SHIFT,
        ST_TOTAL
    };
    
    // Forward declaration
    template <typename T, ScheduleType ST, typename SFINAE>
    class employee_iterator;
    
    struct Employee {
        std::vector<TimeSlot> mFreeTime;
        std::vector<TimeSlot> mShifts;
    
        using timeslot_iterator       = typename std::vector<TimeSlot>::iterator;
        using timeslot_const_iterator = typename std::vector<TimeSlot>::const_iterator;
    
        timeslot_const_iterator begin(const std::vector<TimeSlot>& s) const;
        timeslot_const_iterator end(const std::vector<TimeSlot>& s) const;
    
        timeslot_iterator begin(std::vector<TimeSlot>& s);
        timeslot_iterator end(std::vector<TimeSlot>& s);
    
    };
    
    // Helper class
    template <typename T, ScheduleType ST,
        typename = std::enable_if_t<std::is_same_v<Employee, std::remove_cv_t<T>>>
    >
    struct employee_iterator {
        using iterator = std::conditional_t<std::is_const_v<T>, Employee::timeslot_const_iterator, Employee::timeslot_iterator>;
    
        constexpr static ScheduleType mScheduleType = ST;
    
        std::add_pointer_t<T> mEmployee;
    
        employee_iterator() = delete;
        employee_iterator(T& e);    
        employee_iterator(T* e);
    };
    
    // Helper class c'tors
    template <typename T, ScheduleType ST, typename SFINAE>
    employee_iterator<T, ST, SFINAE>::employee_iterator(T& e) 
        : mEmployee{ &e }
        {  }
    
    template <typename T, ScheduleType ST, typename SFINAE>
    employee_iterator<T, ST, SFINAE>::employee_iterator(T* e)
        : mEmployee{ e }
        {  }
    
    // begin and end functions for iteration over Employee
    template <typename T, ScheduleType ST, typename SFINAE>
    typename employee_iterator<T, ST, SFINAE>::iterator begin(employee_iterator<T, ST, SFINAE> it) {
        if constexpr (ST == FREE)
            return it.mEmployee->begin(it.mEmployee->mFreeTime);
        else
            return it.mEmployee->begin(it.mEmployee->mShifts);
    }
    
    template <typename T, ScheduleType ST, typename SFINAE>
    typename employee_iterator<T, ST, SFINAE>::iterator end(employee_iterator<T, ST, SFINAE> it) {
        if constexpr (ST == FREE)
            return it.mEmployee->end(it.mEmployee->mFreeTime);
        else
            return it.mEmployee->end(it.mEmployee->mShifts);
    }
    
    /// Type alias
    template <typename T>
    using employee_freetime_iterator = employee_iterator<T, FREE>;
    
    template <typename T>
    using employee_shift_iterator = employee_iterator<T, SHIFT>;
    

    编辑:我知道我写的代码又长又混乱,所以我创建了一些非常简短的东西来说明我的问题。我怎样才能让它工作?

    #include <utility>
    
    template <typename T1, typename T2>
    using my_pair = std::pair<T1, T2>;
    
    
    int main() {
        // I can do this:
        // will be inferred as std::pair<double, int>
        std::pair test1{ 1.0, 5 };
    
        // However the compiler has issues with this:
        my_pair test2{1.0, 3};
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   David G    7 年前

    如果需要模板参数推导,则需要引入函数:

    namespace detail{
      // ... employee_iterator, ScheduleType etc, ...
      template <typename T>
      using employee_freetime_iterator = employee_iterator<T, FREE>;
    
      template <typename T>
      using employee_shift_iterator = employee_iterator<T, SHIFT>;
    }
    
    template<class T>
    detail::employee_freetime_iterator<T> employee_freetime_iterator(T& e) {
      return {e};
    }
    
    template<class T>
    detail::employee_shift_iterator<T> employee_shift_iterator(T& e) {
      return {e};
    }