const auto和object constancy

时间:2017-06-19 14:34:40

标签: c++ c++11 const auto

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

写起来非常直观:

const auto result = RetrieveResult();

如果RetrieveResult按值或按引用返回对象,一切正常。但是如果函数返回一个指针,则常量应用于该指针,而不是指向poiter指向的对象。我还能以什么方式改变对象。写

const auto const result = ....

导致编译错误:

  

重复'const'

当然,我可以像这样声明变量:     const auto * ...     const auto * const ...

但这种方式使我与指针紧密相关,即它不是一种通用的解决方案。

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

2 个答案:

答案 0 :(得分:4)

在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示例中使用引用折叠,因此预计在您可能期望elision的情况下至少会发生移动。您可以根据您的使用情况对其进行优化。我只是想我会勾勒出脑海里的东西。也许这会有所帮助

答案 1 :(得分:1)

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

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

这不会将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执行此操作。