Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 基于范围的循环与常量共享\u ptr<&燃气轮机;_C++_Pointers_Iteration_Constants_Container Data Type - Fatal编程技术网

C++ 基于范围的循环与常量共享\u ptr<&燃气轮机;

C++ 基于范围的循环与常量共享\u ptr<&燃气轮机;,c++,pointers,iteration,constants,container-data-type,C++,Pointers,Iteration,Constants,Container Data Type,我有一个带有shared\u ptr的容器,例如一个向量v,我想迭代v以指示常量 此代码: vector<shared_ptr<string>> v; v.push_back(make_shared<std::string>("hallo")); ... for (const auto &s : v) { *s += "."; // <<== should be invalid } (但由于其他原因,此代码无法编译:)) 编

我有一个带有
shared\u ptr
的容器,例如一个
向量
v
,我想迭代
v
以指示常量

此代码:

vector<shared_ptr<string>> v;
v.push_back(make_shared<std::string>("hallo"));
...

for (const auto &s : v) {
    *s += ".";   // <<== should be invalid
}
(但由于其他原因,此代码无法编译:))

编辑:

我犯了一个错误。最初我声明了一个引用,这导致了一个编译器错误

for (shared_ptr<const string> &s : v) {   // <<== does not compile
    ...
}

<代码> >(SyrdHypTr& S:v){//< P>这是C++的一个众所周知的限制,有些不认为是限制。 您希望迭代
const
ly,但不可变指针并不意味着不可变指针对象

类型
shared_ptr
和类型
shared_ptr
实际上是不相关的

选择1
for(常数自动和ptr:v){
const auto&s=*ptr;

s+=“;//我会选择模板法

template <class T,class F>
void forEach(const std::vector<std::shared_ptr<T>>& vec, F&& f){
  for (const auto& ptr : vec){
      if (ptr){
         f(std::cref(*ptr));
     }
  }
}
模板
void forEach(const std::vector&vec,F&F){
用于(常数自动和ptr:vec){
如果(ptr){
f(标准:cref(*ptr));
}
}
}
如果你在那里放了一个lambda函数,编译器可能会将其内联,因此不会对这里的性能造成损害。

答案如下

但首先,布道:

指针和它所指向的对象是两个独立的对象。没有或两者都可能是常量,而常量指针只是表示它不会指向不同的对象。如果指针对象是常量,则不能通过(可能是非常量)指针更改对象

话虽如此,我们(I)经常编写使用
unique\u ptr
shared\u ptr
作为pimpl的值语义包装器对象。我们经常希望将包装器的constness分配给实现

我相信c++17会用它的
propagate\u const
指针包装器解决这个问题

同时,您可以直接构建自己的:

#include <iostream>
#include <type_traits>
#include <memory>
#include <string>
#include <vector>

namespace traits
{
    template<class T> struct pointee;
    template<class T, class D>
    struct pointee<std::unique_ptr<T, D>> {
        using type = T;
    };

    template<class T>
    struct pointee<std::shared_ptr<T>> {
        using type = T;
    };

    template<class T> using pointee_t = typename pointee<T>::type;
}

template<class PointerType>
struct propagate_const
{
    using pointer_type = PointerType;
    using element_type = traits::pointee_t<pointer_type>;
    using value_type = std::decay_t<element_type>;
    using reference = value_type&;
    using const_reference = const value_type&;

    propagate_const(pointer_type p) : _ptr(std::move(p)) {}

    const_reference operator*() const {
        return *_ptr;
    }

    auto operator*()
    -> std::enable_if_t<not std::is_const<element_type>::value, reference>
    {
        return *_ptr;
    }

private:
    pointer_type _ptr;
};

template<class PointerType>
auto make_propagating_pointer(PointerType&& p)
{
    return propagate_const<PointerType>(std::forward<PointerType>(p));
}

int main()
{
    using namespace std;

    vector<propagate_const<shared_ptr<string>>> v;
    v.emplace_back(make_shared<string>("hello"));

    for (const auto& p : v)
    {
//        *p += " there";  // compile error
        cout << *p;
        cout << endl;
    }

    for (auto& p : v)
    {
        *p += " there";
        cout << *p;
        cout << endl;
    }

    return 0;
}
这个非常简单,只支持
操作符*
,但是添加一组完整的操作符并不重要

参考:

为了好玩,这里有一个
shared_string
类的完整示例,它在内部使用
shared_ptr
,并正确地传播constness

#include <iostream>
#include <type_traits>
#include <memory>
#include <string>
#include <vector>

template<class PointerType>
struct propagate_const
{
    using pointer_type = PointerType;
    using element_type = std::remove_reference_t<decltype(*std::declval<PointerType&>())>;
    using reference = element_type&;
    using const_reference = const element_type&;

    propagate_const(pointer_type p) : _ptr(std::move(p)) {}

    const_reference operator*() const {
        return *_ptr;
    }

    auto operator*()
    -> std::enable_if_t<not std::is_const<element_type>::value, reference>
    {
        return *_ptr;
    }

private:
    pointer_type _ptr;
};

template<class PointerType>
auto make_propagating_pointer(PointerType&& p)
{
    return propagate_const<PointerType>(std::forward<PointerType>(p));
}

struct shared_string
{
    shared_string(std::string s) : _impl(std::make_shared<std::string>(std::move(s))) {};
    shared_string(std::shared_ptr<std::string> sp) : _impl(sp) {};
    shared_string(propagate_const<std::shared_ptr<std::string>> sp) : _impl(sp) {};

    auto& operator += (const std::string& s) {
        *_impl += s;
        return *this;
    }

    friend std::ostream& operator<<(std::ostream& os, const shared_string& ss) {
        return os << *(ss._impl);
    }

private:
    propagate_const<std::shared_ptr<std::string>> _impl;
};

template<class T, std::enable_if_t<std::is_const<T>::value>* = nullptr >
std::string check_const(T&)
{
    return std::string("const");
}

template<class T, std::enable_if_t<not std::is_const<T>::value>* = nullptr >
std::string check_const(T&)
{
    return std::string("not const");
}

int main()
{
    using namespace std;

    // a vector of mutable shared_strings
    vector<shared_string> v;

    // a vector of immutable shared_strings
    vector<const shared_string> cv;

    // make a shared_string
    v.emplace_back(make_shared<string>("hello"));

    // refer to the *same one* in cv
    cv.emplace_back(v[0]);

    for (const auto& p : v)
    {
//        *p += " there";  // immutable reference to mutable shared string - not allowed
        cout << check_const(p) << " " << p;
        cout << endl;
    }

    for (auto& p : v)
    {
        cout << check_const(p) << " " << p;
        p += " there";    // mutable reference to mutable shared string - allowed
        cout << " becomes " << p;
        cout << endl;
    }

    for (auto&p : cv)
    {
        cout << check_const(p) << " " << p;
//        p += " world";     // p is actually immutable because cv contains immutable objects
        cout << endl;
    }

    return 0;
}

不过,这些类型并不像你所说的那样毫无关联。如果你真的想,你可以写:
for(const auto&p:std::vector(v.begin(),v.end()){/*…*/}
@KerrekSB:当然,它们之间存在一个转换路径。正如你可以从
int
转换为
float
。但这两种类型仍然不同,区别超出了cv限定。就像这里一样。如果
ptr
为空,它不会导致未定义的行为吗?因为似乎没有单一的状态如果不复制指针,就无法接近你的选项1。因此,我给出了答案。大卫指出的这两个陈述和风险让人感觉不好。@DavidHaim:是的,但不比原始代码更糟。
for(shared_ptr s:v){*s+=”;}
?在我看来,您的类似示例正是您所需要的,那么您的问题是什么?@cppleener它不起作用,是主要的缺陷。@Lightness第一个示例说
*s+=”;//我从类型为'std::shared_ptr'的表达式中获取了一个
main.cpp:14:error:std::shared_ptr&'类型引用的初始化无效(
error)
行-但我看到了问题:我已经声明了一个参考:
共享的\u ptr&s
+1用于
传播常数
提示,但是你的答案对我来说似乎有点冗长。但是对于更大的API,这可能是一种方法。@frans谢谢。人们永远不知道答案要走多远,所以以防万一有人问同样的问题n如果人们感兴趣,我想提供一个扩展的答案。
#include <iostream>
#include <type_traits>
#include <memory>
#include <string>
#include <vector>

namespace traits
{
    template<class T> struct pointee;
    template<class T, class D>
    struct pointee<std::unique_ptr<T, D>> {
        using type = T;
    };

    template<class T>
    struct pointee<std::shared_ptr<T>> {
        using type = T;
    };

    template<class T> using pointee_t = typename pointee<T>::type;
}

template<class PointerType>
struct propagate_const
{
    using pointer_type = PointerType;
    using element_type = traits::pointee_t<pointer_type>;
    using value_type = std::decay_t<element_type>;
    using reference = value_type&;
    using const_reference = const value_type&;

    propagate_const(pointer_type p) : _ptr(std::move(p)) {}

    const_reference operator*() const {
        return *_ptr;
    }

    auto operator*()
    -> std::enable_if_t<not std::is_const<element_type>::value, reference>
    {
        return *_ptr;
    }

private:
    pointer_type _ptr;
};

template<class PointerType>
auto make_propagating_pointer(PointerType&& p)
{
    return propagate_const<PointerType>(std::forward<PointerType>(p));
}

int main()
{
    using namespace std;

    vector<propagate_const<shared_ptr<string>>> v;
    v.emplace_back(make_shared<string>("hello"));

    for (const auto& p : v)
    {
//        *p += " there";  // compile error
        cout << *p;
        cout << endl;
    }

    for (auto& p : v)
    {
        *p += " there";
        cout << *p;
        cout << endl;
    }

    return 0;
}
hello
hello there
#include <iostream>
#include <type_traits>
#include <memory>
#include <string>
#include <vector>

template<class PointerType>
struct propagate_const
{
    using pointer_type = PointerType;
    using element_type = std::remove_reference_t<decltype(*std::declval<PointerType&>())>;
    using reference = element_type&;
    using const_reference = const element_type&;

    propagate_const(pointer_type p) : _ptr(std::move(p)) {}

    const_reference operator*() const {
        return *_ptr;
    }

    auto operator*()
    -> std::enable_if_t<not std::is_const<element_type>::value, reference>
    {
        return *_ptr;
    }

private:
    pointer_type _ptr;
};

template<class PointerType>
auto make_propagating_pointer(PointerType&& p)
{
    return propagate_const<PointerType>(std::forward<PointerType>(p));
}

struct shared_string
{
    shared_string(std::string s) : _impl(std::make_shared<std::string>(std::move(s))) {};
    shared_string(std::shared_ptr<std::string> sp) : _impl(sp) {};
    shared_string(propagate_const<std::shared_ptr<std::string>> sp) : _impl(sp) {};

    auto& operator += (const std::string& s) {
        *_impl += s;
        return *this;
    }

    friend std::ostream& operator<<(std::ostream& os, const shared_string& ss) {
        return os << *(ss._impl);
    }

private:
    propagate_const<std::shared_ptr<std::string>> _impl;
};

template<class T, std::enable_if_t<std::is_const<T>::value>* = nullptr >
std::string check_const(T&)
{
    return std::string("const");
}

template<class T, std::enable_if_t<not std::is_const<T>::value>* = nullptr >
std::string check_const(T&)
{
    return std::string("not const");
}

int main()
{
    using namespace std;

    // a vector of mutable shared_strings
    vector<shared_string> v;

    // a vector of immutable shared_strings
    vector<const shared_string> cv;

    // make a shared_string
    v.emplace_back(make_shared<string>("hello"));

    // refer to the *same one* in cv
    cv.emplace_back(v[0]);

    for (const auto& p : v)
    {
//        *p += " there";  // immutable reference to mutable shared string - not allowed
        cout << check_const(p) << " " << p;
        cout << endl;
    }

    for (auto& p : v)
    {
        cout << check_const(p) << " " << p;
        p += " there";    // mutable reference to mutable shared string - allowed
        cout << " becomes " << p;
        cout << endl;
    }

    for (auto&p : cv)
    {
        cout << check_const(p) << " " << p;
//        p += " world";     // p is actually immutable because cv contains immutable objects
        cout << endl;
    }

    return 0;
}
const hello
not const hello becomes hello there
const hello there