【问题标题】:Adding a const qualifier to a member function向成员函数添加 const 限定符
【发布时间】:2012-04-11 16:30:48
【问题描述】:

我目前正在编写一个接口类,它应该提供对复杂结构的内部元素的访问,作为 const 或非 const 引用。这个想法是一些模块被授予 const 访问权限,而一些模块被授予完全访问权限。

我已经使用 'type_traits' 'std::add_const' 有条件地限定内部成员函数的返回类型,不幸的是我想不出有条件地将成员函数限定为 const 或非 const 的方法。

这甚至可能吗?如果是这样怎么办?

例如:

template< typename T, bool isConst  >
struct apply_const
{
    typedef T type;
};

template<typename T>
struct apply_const<T, true>
{
    typedef typename std::add_const<T>::type type;
};

template< bool isConst >
const Interface
{
    /// @brief get the TypeA member
    typename apply_const<TypeA, isConst >::type& GetXpo3Container()  // how do I conditionally add a const qualifier
    {
        return config_.type_a_member_;
    }

    typename apply_const<Profile, isConst >::type& GetProfile( unint32_t id )  // qualifier ???
    {
        return config_.profiles.get( id );
    }

    // .... lots more access functions

    ConfigType config_; // the config
};

注意:分离/创建两个版本的接口的根本原因是它们将提供对config 不同实例的访问——一个是可写的,一个是不可写的。正在开发的子系统是一个嵌入式Netconf Agent,支持&lt;running&gt;和&lt;candidate&gt;配置。

【问题讨论】:

  • 使用两个重载(一个 const 和一个非常量),并使用 SFINAE 一次只启用其中一个。
  • 2 个重载实际上并没有保存任何东西(如下所述)。目标是提供 2 个版本的“接口”,一种是所有成员函数都返回“const”引用,另一种是所有成员函数都返回非 const 引用。返回类型的常量性不仅仅是成员函数的限定问题。我想我只需要对成员函数没有限制就可以了,这不是太大的问题。

标签: c++ templates c++11 template-meta-programming typetraits


【解决方案1】:

这似乎通过专业化最容易做到:

template< bool isConst >
struct Interface;

template <>
struct Interface<false>
{
    TypeA& GetXpo3Container()
    {
        return config_.type_a_member_;
    }
};

template <>
struct Interface<true>
{
    const TypeA& GetXpo3Container() const
    {
        return config_.type_a_member_;
    }
};

编辑:虽然我不完全确定这增加了什么。是不是更容易拥有

struct Interface
{
    TypeA::type& GetXpo3Container()
    {
        return config_.type_a_member_;
    }
    const TypeA::type& GetXpo3Container() const
    {
        return config_.type_a_member_;
    }
};

并在适当的地方使用const Interface?还是出于其他原因,这不是一种选择?

编辑 2:我的 std::enable_if 使用错误,现在已经消失了。

【讨论】:

  • 这将产生硬错误,而不是软错误,因为std::enable_if&lt;isConst, TypeA&gt;::type 不依赖于Interface 的范围(其他情况也是如此)。
  • @LucDanton 当你发表评论时我实际上正在编辑,但是谢谢,你是对的 :)
【解决方案2】:

您可以使用 SFINAE:

template<bool isConst>
struct Interface
{
    template<
        bool Cond = isConst
        , typename std::enable_if<!Cond, int>::type = 0            
    >
    TypeA&
    GetXpo3Container() const
    {
        return config_.type_a_member_;
    }

    template<
        bool Cond = isConst
        , typename std::enable_if<Cond, int>::type = 0
    >
    TypeA const&
    GetXpo3Container() const
    {
        return config_.type_a_member_;
    }
};

请注意,这两个成员需要成为模板,并且我正在使用默认参数来强制 typename std::enable_if&lt;Cond, int&gt;::type 依赖——在 std::enable_if&lt;isConst, int&gt;::type 类的范围内 不是依赖,因此在我们需要 SFINAE 的情况下实例化类时会产生硬错误。

然而,默认参数意味着某人可以做例如Interface&lt;true&gt; f; TypeA&amp; ref = f.GetXpo3Container&lt;false&gt;();。如果您想避免这种情况(例如,您不相信用户不会滥用您的界面中未指定的部分),这是另一种让 std::enable_if 的成员 type 再次依赖的方法,这可能更合适,但更神秘:

template<typename T, T Value, typename>
struct depend_on_c {
    static constexpr T value = Value;
};

/* and in the scope of Interface: */
    template<
        typename Dummy = void
        , typename std::enable_if<
            depend_on_c<bool, isConst, Dummy>::value
            , int
         >::type = 0
    >
    /* rest as before */

【讨论】:

    【解决方案3】:

    您可以针对isConst 为真的情况专门化您的模板,并在这种情况下将所有成员函数设为const,同时在主模板中保留非const。

    或者,编写两个版本的成员函数(一个 const 和一个不),并使用 enable_if 仅启用适当的重载。

    【讨论】:

      猜你喜欢
      • 2020-03-24
      • 1970-01-01
      • 2014-05-25
      • 2014-06-06
      • 2017-05-20
      • 2011-06-04
      • 2016-08-17
      • 2019-09-14
      • 2014-10-18
      相关资源
      最近更新 更多