通过类型别名从构造函数转发模板推导
Forward template deduction from constructor through type-alias
这个问题关于 C++ 的语法以及如何做一些具体的事情。
我有一个 Employee
class,其中有 2 个数组成员函数。一个数组存储 Employee
拥有的所有空闲时间,另一个存储 Employee
涵盖的班次。我想定义一个帮助程序 class,让我可以在任一数组上使用 for range 循环 (for (:)
)。例如,如果我这样做:
for (auto& ts : employee_freetime_iterator{ employee })
它将遍历员工的空闲时间。如果我这样做:
for (auto& ts : employee_shift_iterator{ employee })
它将迭代轮班。我有一个 class 定义如下:
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
将成为 Employee
或 const Employee
,并且第三个模板参数是 SFINAE 以强制执行此事实。现在,如果我使用这个 class,那么我将不得不复制并粘贴它两次,一次用于 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
选择不同的辅助函数,让我迭代 Employee
class。我想要做的是创建 2 个不同类型的别名(每个 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>;
但是我如何转发构造函数参数以便自动推断 T
模板参数?只是按原样编译给我这个错误:
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};
}
如果需要模板参数推导需要引入函数:
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};
}
不幸的是class模板类型别名不允许模板参数推导。如果您想放弃显式模板参数,则必须使用函数模板。
这个问题关于 C++ 的语法以及如何做一些具体的事情。
我有一个 Employee
class,其中有 2 个数组成员函数。一个数组存储 Employee
拥有的所有空闲时间,另一个存储 Employee
涵盖的班次。我想定义一个帮助程序 class,让我可以在任一数组上使用 for range 循环 (for (:)
)。例如,如果我这样做:
for (auto& ts : employee_freetime_iterator{ employee })
它将遍历员工的空闲时间。如果我这样做:
for (auto& ts : employee_shift_iterator{ employee })
它将迭代轮班。我有一个 class 定义如下:
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
将成为 Employee
或 const Employee
,并且第三个模板参数是 SFINAE 以强制执行此事实。现在,如果我使用这个 class,那么我将不得不复制并粘贴它两次,一次用于 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
选择不同的辅助函数,让我迭代 Employee
class。我想要做的是创建 2 个不同类型的别名(每个 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>;
但是我如何转发构造函数参数以便自动推断 T
模板参数?只是按原样编译给我这个错误:
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};
}
如果需要模板参数推导需要引入函数:
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};
}
不幸的是class模板类型别名不允许模板参数推导。如果您想放弃显式模板参数,则必须使用函数模板。