无法创建 constexpr getter

问题描述 投票:0回答:1

我有一个包含多个

std::set
数据的结构。我想访问要在编译时计算的集合。为此,我创建了一个模板化
constexpr
方法来返回请求的集。

// 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();

这会导致错误:

错误:将“const TwoSets”作为“this”参数传递会丢弃限定符[-fpermissive]

可以通过将

get
标记为
const
/返回
const
引用来修复此问题,这会破坏插入代码。我需要做什么才能两者兼得

  1. 在编译时执行集合选择
  2. 使用可变引用和 const 不可变引用访问集合
c++ constexpr
1个回答
0
投票

我需要做什么才能两者兼得

  1. 在编译时执行集合选择。
  2. 使用可变引用和
    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] 之前,您需要

  1. 同时提供
    const
    和非
    const
    getter 成员,
  2. 或将共同逻辑移至非成员
    friend

将通用逻辑移至非成员

friend
看起来像:

// Forward declaration
struct TwoSets;
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;
};

// 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愚蠢!”

© www.soinside.com 2019 - 2024. All rights reserved.