想象一下一些函数(RetrieveResult
),通过指针/引用/值返回一个对象 - 我不知道也不想知道,因为事情可能会改变。我只想使用auto
存储结果,并保护该对象不会在当前范围内意外更改,或者,例如,如果对象向上传播。
写起来非常直观:
const auto result = RetrieveResult();
如果RetrieveResult
按值或按引用返回对象,一切正常。但是如果函数返回一个指针,则常量应用于该指针,而不是指向poiter指向的对象。我还能以什么方式改变对象。写
const auto const result = ....
导致编译错误:
重复'const'
当然,我可以像这样声明变量: const auto * ... const auto * const ...
但这种方式使我与指针紧密相关,即它不是一种通用的解决方案。
是否有可能保持真正的恒定性,同时提供灵活性(具体类型的独立性)?
答案 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>; };
将针对unique
和shared
执行此操作。