我有一个包含多个
std::set
数据的结构。我希望访问要在编译时计算的集合。为此,我创建了一个模板 constexpr
getter 方法来返回请求的集。
// simplified sample
struct TwoSets
{
template <int i> constexpr std::set<int> &get() noexcept
{
if constexpr (i == 0) {
return first;
} else if constexpr (i == 1) {
return second;
} else {
static_assert(i == 0 || i == 1, "invalid");
}
}
std::set<int> first;
std::set<int> second;
};
这是可行的,但有些代码会插入给定的集合,而有些代码需要通过对集合的
const
引用来只读访问该集合,如下所示:
TwoSets sets;
sets.get<0>().insert(0);
// ...elsewhere in code
const TwoSets &const_sets = sets;
std::cout << const_sets.get<0>().size();
这会导致错误:
error: passing ‘const TwoSets’ as ‘this’ argument discards qualifiers [-fpermissive]
可以通过将
get
标记为 const
/返回 const
引用来修复此问题,这会破坏插入代码。我需要做什么才能两者兼得
const
不可变引用访问集合我需要做什么才能两者兼得
- 在编译时执行集合选择。
- 使用可变引用和
不可变引用访问集合。const
this
是此类场景的完美解决方案。
struct TwoSets
{
template <int i, typename Self>
constexpr auto&& get(this Self&& self ) noexcept
{
if constexpr (i == 0) {
return std::forward<Self>(self).first;
}
else if constexpr (i == 1) {
return std::forward<Self>(self).second;
}
else {
static_assert(i == 0 || i == 1, "invalid");
}
}
std::set<int> first{};
std::set<int> second{};
};
但是,在 [tag:C++:23] 之前,您需要
const
和非 const
getter 成员,friend
或内部函数。将通用逻辑转移到函数中看起来像:
// Forward declaration
struct TwoSets;
// some internal namespace
template<int i, typename T> constexpr auto& getSet(T&&) noexcept;
struct TwoSets
{
template <int i>
constexpr std::set<int>& get() noexcept {
return getSet<i>(*this);
}
template <int i>
constexpr const std::set<int>& get() const noexcept {
return getSet<i>(*this);
}
std::set<int> first;
std::set<int> second;
};
// some internal namespace
// Friend function to get the set from TwoSets
template<int i, typename T>
constexpr auto& getSet(T&& sets) noexcept
{
// ... code
}
旁注:如果您的实际情况如图所示,您应该考虑
std::tuple
正如@paddy 在评论中建议的那样,并且 Keep It Simple, & S愚蠢!”