我有一个包含元组的类:
template <typename ... Args>
struct Point {
std::tuple<Args...> data;
...
};
在内部,我需要一些创建数据视图的方法。例如,当数据具有一维或更多维时,最好有一个名为x
和y
的方法来提取第一个和第二个元素:
template <typename ... Args>
struct Point {
std::tuple<Args...> data;
using value_type = decltype(data);
template<typename T = typename std::tuple_element<0, value_type>::type>
T &x() {
return std::get<0>(data);
}
template<typename T = typename std::tuple_element<1, value_type>::type>
T &y() {
return std::get<1>(data);
}
};
问题在于元组大小。当元组的大小小于访问器的大小时,我无法弄清楚如何使用SFINAE不提供此方法。例如,如果您创建尺寸超过1个维度的点(例如Point<float,int>
),则上述类可以很好地工作。但是,如果您尝试创建Point<float>
,则代码将无法编译。具体来说,在GCC 8.2中,我收到了编译器错误:
no type named 'type' in 'struct std::tuple_element<1, std::tuple<float> >'
我也尝试过这样的成语:
auto y() -> typename std::tuple_element<1, value_type>::type {
return std::get<1>(data);
}
但是我得到了相同的编译器错误。
答案 0 :(得分:3)
SFINAE中的“ S”代表“替代”。因此,您需要确保在替换期间进行检查。您可以通过引入默认为value_type
的额外模板参数来做到这一点:
template<typename U = value_type, typename T = typename std::tuple_element<0, U>::type>
T &x() {
return std::get<0>(data);
}
template<typename U = value_type, typename T = typename std::tuple_element<1, U>::type>
T &y() {
return std::get<1>(data);
}
答案 1 :(得分:2)
在C ++ 20中,由于requires
,您可以“丢弃”方法:
template <typename ... Args>
struct Point {
std::tuple<Args...> data;
decltype(auto) x() requires (sizeof...(Args) > 0) { return std::get<0>(data); }
decltype(auto) y() requires (sizeof...(Args) > 1) { return std::get<1>(data); }
};