【问题标题】:const auto and object constancyconst auto 和对象恒常性
【发布时间】:2017-06-19 14:34:39
【问题描述】:

想象一些函数(RetrieveResult),通过指针/引用/值返回一个对象——我不知道也不想知道,因为事情可能会改变。我只想使用auto 存储结果,并保护该对象免受当前范围内的意外更改,或者例如,如果该对象向上传播。

写起来很直观:

const auto result = RetrieveResult();

如果RetrieveResult 按值或引用返回对象,一切正常。但是,如果函数返回一个指针,则恒常适用于该指针,而不是指针指向的对象。我仍然可以通过什么方式更改对象。写作

const auto const result = ....

导致编译错误:

重复的“常量”

当然,我可以像这样声明变量: 常量自动* ... 常量自动*常量...

但这种方式将我与指针联系在一起,即它不是一个通用的解决方案。

是否可以保持真正的恒定性,同时提供灵活性(具体类型的独立性)?

【问题讨论】:

  • "我不知道也不想知道" 如果您不知道对象是什么,您应该如何访问它?据你所知,它可能是一个重载-> 的类,你认为它是一个指针:P
  • @Rakete1111,例如,我可能只是转发对象,而不是触摸它
  • @Alexey 如果你转发它,你为什么关心它指向的指针是否是const
  • 在 VS2015 中,const auto const 不会产生任何编译器错误,只是一个警告:warning C4114: same type qualifier used more than once
  • @Rakete1111, 总有一些原因 ) C++ 有强大的语法,我正试图感知所有这些魔鬼的东西)

标签: c++ c++11 constants auto


【解决方案1】:

Library Fundamentals v2 中有对这个名为 std::propagate_const 的实用程序的实验性支持。您可以在此之上编写一个类型特征来为您执行此操作(如果您没有std::propagate_const,您可以考虑自己编写它:))

namespace {
    template <typename T, typename = std::enable_if_t<true>>
    PropagateConst {
        using type = T;
    };
    template <typename T>
    PropagateConst<T, std::enable_if_t<std::is_same<
            decltype(*std::declval<std::decay_t<T>>()), 
            decltype(*std::declval<std::decay_t<T>>())>::value>> {
        using type = std::propagate_const_t<std::decay_t<T>>;
    };

    template <typename T>
    using PropagateConst_t = typename PropagateConst<T>::type;

    template <typename Type>
    decltype(auto) propagate_const(Type&& in) {
        return PropagateConst_t<std::add_rvalue_reference_t<Type>>{in};
    }
} // <anonymous>

// then use it like this
const auto result = propagate_const(RetrieveResult());

请注意,我上面的解决方案仅检查可能的指针类型中是否存在operator*。您可能需要考虑为此编写更广泛的测试。

另请注意,这在propagate_const 示例中使用了引用折叠,因此在您可能期望省略的情况下,至少会发生一次移动。您可以根据您的用例对其进行优化。我只是想我会勾勒出我脑子里的东西。也许这会有所帮助

【讨论】:

    【解决方案2】:
    template<class T>
    struct very_const_t { using type=T; };
    template<class T>
    struct very_const_t<T*> { using type=typename very_const_t<T>::type const*; };
    template<class T>
    struct very_const_t<T&> { using type=typename very_const_t<T>::type const&; };
    
    template<class T>
    typename very_const_t<T>::type&&
    very_const( T&& t ) { return std::forward<T>(t); }
    

    然后:

    const auto result = very_const(RetrieveResult());
    

    请注意,这可以阻止省略。但是,我小心地不阻止移动语义。

    这不会将const 移动到智能指针中。如果你想要:

    template<class T, class D>
    struct very_const_t<std::unique_ptr<T,D>> { using type=std::unique_ptr<typename very_const_t<T>::type const, D>; };
    
    template<class T>
    struct very_const_t<std::shared_ptr<T>> { using type=std::shared_ptr<typename very_const_t<T>::type const>; };
    

    将为uniqueshared 执行此操作。

    【讨论】:

      猜你喜欢
      • 2021-09-23
      • 2012-05-29
      • 2016-08-02
      • 1970-01-01
      • 2016-11-14
      • 2011-05-06
      • 1970-01-01
      • 2017-02-28
      相关资源
      最近更新 更多