无法创建多个 constexpr getter

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

我有一个包含多个

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
引用来修复此问题,这会破坏插入代码。我需要做什么才能两者兼得

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

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

  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
    或内部函数。

将通用逻辑转移到函数中看起来像:

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

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