在初始化表达式中强制左值的const-ness

C++ Force const-ness of lvalue in initializer expression

本文关键字:const-ness 初始化 表达式      更新时间:2023-10-16

我希望编译器强制左值(非引用)的const-ness,但不知道这在c++中是否可能。一个例子:

int foo() { return 5; }
int main() {
  // Is there anything I can add to the declaration of foo()
  // that would make the following cause a compile-error?
  int a = foo();
  // Whereas this compiles fine.
  const int a = foo();
}

对于像int这样的对象来说,这是不可能的,因为你需要允许读取int型,如果他们可以读取int型,那么他们可以将其复制到非const int型。

但是从你的评论中听起来,你在现实中拥有的不是int,而是更复杂的用户定义类型,某种容器。您可以轻松地创建不可变容器。该容器可以是包装器,也可以是现有容器的替代实现。无论调用者使用const还是非const变量,它仍然是不可变的。

class MyClass {
  std::vector<int> data;
public:
  MyClass(size_t size) : data(size) {}
  int& operator[](size_t index) { return data[index]; }
  int operator[](size_t index) const { return data[index]; }
  size_t size() const { return data.size(); }
};
class MyClassImmutable {
  MyClass mc;
public:
  MyClassImmutable(MyClass&& mc) : mc(std::move(mc)){}
  int operator[](size_t index) const { return mc[index]; }
  size_t size() const { return mc.size(); }
  const MyClass& get() const { return mc; }
};
MyClassImmutable foo() {
  MyClass mc(100);
  mc[10] = 3;
  return mc;
}
void func(const MyClass& mc);
int main() {
    MyClassImmutable mci = foo();
    std::cout << mci[10] << "n";  // Can read individual values
    //mci[10] = 4; // Error immutable
    func(mc.get());  // call function taking a const MyClass&
}

现场演示。

当然,没有什么可以阻止调用者从不可变容器中复制每个值并将它们插入到可变容器中。

Edit:另一种方法可能是返回指向const的智能指针。唯一的缺点是您必须为动态内存分配付费:

std::unique_ptr<const MyClass> foo() {
  auto mc = std::make_unique<MyClass>(100);
  (*mc)[10] = 3;
  return mc;
}
void func(const MyClass& mc);
int main() {
    auto mc = foo();
    std::cout << (*mc)[10] << "n";  // Can read individual values
    //(*mc)[10] = 4; // Error const
    func(*mc);  // can pass to a function taking a const MyClass&
}

不可能。foo()无法知道左侧赋值的类型,因为当赋值发生时,foo()已经被求值了。最好的情况是更改返回值,尝试在初始化时导致基于类型的错误:

#include <type_traits>
struct my_int {
  const int m;
  template<typename T, typename std::enable_if<std::is_const<T>::value, T>::type* = nullptr>
  constexpr operator T() const {return m;}
};
constexpr my_int foo() { return {5};}
int main() {
  const int a = foo();
  int b = foo();
}

生活例子

但是这也行不通,因为模板中的typename永远不会被const限定类型所替换(在本例中,main()中的两行都是int)。

如下所示

const int x = 4;
int y = x;

c++语言不会提供这样的机制。

通过宏机制保持int const。

#define int_const_foo(var) const int var = ___foo()
int_const_foo(a);

缺点:foo不能隐藏,语法也不再是C风格了