C++ 强制初始化表达式中左值的常量性
C++ Force const-ness of lvalue in initializer expression
我希望编译器强制执行左值(非引用)的常量性,但不知道这在 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();
}
这不可能。 foo()
无法知道赋值左侧的类型,因为当赋值本身发生时,foo()
已经求值了。您最好的希望是更改 return 值,尝试在初始化时导致基于类型的错误:
#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();
}
但这也行不通,因为模板中的类型名永远不会被 const 限定的类型替换(在这种特定情况下,[=14= 中的两行都是 int
]).
对于像 int
这样的东西,这实际上是不可能的,因为您需要授予读取 int 的权限,如果他们可以读取 int,那么他们可以将其复制到非常量 int 中。
但是从您的评论看来,您实际上拥有的不是 int
,而是更复杂的用户定义类型,也许是某种容器。您可以轻松地创建不可变容器。该容器可以是包装器,也可以是现有容器的替代实现。那么无论调用者使用 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&
}
当然,没有什么可以阻止调用者从不可变容器中复制每个值并将它们插入可变容器中。
编辑: 另一种方法可能是 return 一个指向常量的智能指针。唯一的缺点是您必须为动态内存分配付费:
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&
}
因为以下是可能的
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风格
我希望编译器强制执行左值(非引用)的常量性,但不知道这在 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();
}
这不可能。 foo()
无法知道赋值左侧的类型,因为当赋值本身发生时,foo()
已经求值了。您最好的希望是更改 return 值,尝试在初始化时导致基于类型的错误:
#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();
}
但这也行不通,因为模板中的类型名永远不会被 const 限定的类型替换(在这种特定情况下,[=14= 中的两行都是 int
]).
对于像 int
这样的东西,这实际上是不可能的,因为您需要授予读取 int 的权限,如果他们可以读取 int,那么他们可以将其复制到非常量 int 中。
但是从您的评论看来,您实际上拥有的不是 int
,而是更复杂的用户定义类型,也许是某种容器。您可以轻松地创建不可变容器。该容器可以是包装器,也可以是现有容器的替代实现。那么无论调用者使用 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&
}
当然,没有什么可以阻止调用者从不可变容器中复制每个值并将它们插入可变容器中。
编辑: 另一种方法可能是 return 一个指向常量的智能指针。唯一的缺点是您必须为动态内存分配付费:
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&
}
因为以下是可能的
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风格