C++:根据模板参数设置指针的常量

C++: setting constness of pointer based on template parameter

本文关键字:设置 指针 常量 参数 C++      更新时间:2023-10-16

我有一个结构,它将"视图"管理到变量类型的数组中。这样做的目的是为ODE模拟提供一个统一的状态向量,同时以有组织的方式处理来自其他几个类的该向量的各个片段。如果这在你的脑海中触发了一个设计模式,请告诉我。

我的问题是,使用Cont::pointer的第一个实现ContainerHolderFirst不编译常量数组。我下一次尝试使用std::conditional,在Cont::const_pointer中混合仍然不起作用。只有第三次尝试使用std::conditional和修改Cont::value_type才能编译(并且似乎在我的更大项目中有效)。我的问题如下:

  • 如果ContainerHolderFirst能工作就好了。我希望类型的常量能够传播到指针。为什么不是
  • 我更不明白ContainerHolderSecond为什么不起作用。中的解释https://stackoverflow.com/a/1647394/1707931相反,这表明这是一条路,不是吗
  • 第三种方法是否存在我尚未发现的问题?有没有更简单的方法

完整的C++11代码如下:

Update1:修复ContainerHolderSecond。它在正确初始化的情况下进行编译。还添加了Barry使用decltypedeclval建议的ContainerHolderBarry。这就留下了这样一个问题:是否有任何一种方法是首选的?它们会导致性能差异吗?它们都应该编译到同一个对象,不是吗?

#include <iostream>
#include <array>
template <typename Cont>
class ContainerHolderFirst {
    Cont& data_;
    const static size_t offset_ = 1;
    typename Cont::pointer data_view;
 public:
    ContainerHolderFirst(Cont& data) : data_(data), data_view(&data[offset_]) {}
};
template <typename Cont>
class ContainerHolderSecond {
    using Pointer = typename std::conditional<std::is_const<Cont>::value,
          typename Cont::const_pointer,
          typename Cont::pointer>::type;
    Cont& data_;
    const static size_t offset_ = 1;
    Pointer data_view;
 public:
    ContainerHolderSecond(Cont& data) : data_(data), data_view(&data[offset_]) {}
};
template <typename Cont>
class ContainerHolderBarry {
    using Pointer = decltype(&std::declval<Cont&>()[0]);
    Cont& data_;
    const static size_t offset_ = 1;
    Pointer data_view;
 public:
    ContainerHolderBarry(Cont& data) : data_(data), data_view(&data[offset_]) {}
};

int main() {
    using namespace std;
    array<int, 2> my_array;
    ContainerHolderFirst<array<int, 2>> holder(my_array); // works
    const array<int, 2> const_array{5,7};
    // ContainerHolderFirst<const array<int, 2>> const_holder(const_array);
    /* error: invalid conversion from 'const value_type* {aka const int*}' to 'std::array<int, 2ull>::pointer {aka int*}' [-fpermissive] */
    ContainerHolderSecond<array<int,2>> second_holder(my_array); // works!
    ContainerHolderSecond<const array<int,2>> const_holder(const_array); //updated; works as well; awkward
    ContainerHolderThird<array<int,2>> third_holder(my_array); // still works
    ContainerHolderThird<const array<int,2>> third_const_holder(const_array); //finally compiles as well
    ContainerHolderBarry<array<int,2>> barry_holder(my_array);
    ContainerHolderBarry<const array<int,2>> barry_const_holder(const_array);
}

你让这件事变得不必要了。如果您想要&cont[offset]的类型,只需询问该表达式的类型即可。将std::declvaldecltype:一起使用

template <typename Cont>
class ContainerHolder {
    using Pointer = decltype(&std::declval<Cont&>()[0]);
    ...
};

ContainerHolderSecond的唯一问题是您使用错误:

ContainerHolderSecond<array<int,2>> const_holder(const_array);
//                    ^-- insert "const" here

至于ContainerHolderFirstarray<T, N>::pointer(array<T, N> const)::pointer是同一类型的原因是没有自动的方法来确定const限定应该添加到嵌套类型的哪里,也没有语言工具来描述这一点(也就是说,我们没有const限定的typedef或类型别名)。