在声明变量后,是否有一种方法将其设置为const?

3
有时在C或C++中,我们可能有一个变量可能是const,但我们必须花费一些代码行来初始化它。
是否有一种方法告诉编译器,在函数的某个点之后,一些已经构造的变量必须被视为const,直到其作用域结束?
类似于:

可能重复:
有没有什么忍者技巧可以使变量在声明后成为常量?

像这样的东西:

int c = 0;
// the value of c is initialized here
switch(someVar) {
   case foo: c = 3; break;
   case bar: c = 4; break;
   default : c = 42; // what else?
}
// now c is constant
ASSUME_CONST_FROM_NOW(c) // some #pragma maybe?

我知道我可以在专门的函数中初始化变量。但这并不是我要问的。
另一个例子:
int c = 0; int d = 0;
{ /*some block of code that initializes both c and d jointly*/ }
ASSUME_CONST_FROM_NOW(c, d)

没有函数可以在不创建结构体或类的情况下同时返回两个值。

但是这种技巧可能会有用,以便使旧的、糟糕的代码更容易理解,而不需要进行太多的重构。


@MSalters:谢谢,我之前没有看到过这个。 - Benoit
为什么你想要这样做呢?更具体地说,为什么它如此重要,以至于你愿意使用非标准和不可移植的#pragma来实现这一点?无论如何,在C语言中,你不能将一个非常量变量"constify"。一旦一个变量是非常量的,你可以(如果需要的话)安全地强制转换去掉任何const限定符以访问该变量。 - eq-
这并不是完全的复制,因为这个问题中没有提示允许使用C++0x解决方案。试图为另一个问题想出一个复杂的C++03解决方案将会是一个糟糕/不必要复杂的答案。对于当前陈述的这个问题,这将是一个必要的复杂答案。 - Johannes Schaub - litb
3个回答

9

是的。

将初始化放在一个函数中。

int getInitCValue(int const& someVar)
{
    // the value of c is initialized here
    switch(someVar)
    {
        case foo: return 3;
        case bar: return 4;
        default : return 42; // what else?
    }
}

int const c = getInitCValue(someVar);

编辑:回答修改后的问题。

您想要初始化两个值:

std::pair<int,int> const value = initalizePairOfValues(someValue);
int const& c = value.first;
int const& d = value.second;

编辑2:采用彼得·托罗克(Péter Török)删除的解决方案(如果Peter取消删除,我将删除此内容)。

struct ConstValues
{
    ConstValues()
    {
         switch(....)
         // Initialize C/D
    }
    int const& getC() const {return c;}
    int const& getD() const {return d;}
    private:
       int c;
       int d;
};

1
你的意思是通过函数进行初始化吗? - Nim
这正是我在问题结尾所说的。我知道这是我应该做的方式。但有时候这个建议会导致太多的工作量。有时候也可以同时初始化两个变量。 - Benoit
@Benoit:你说得对,如果不使用类,是无法返回两个值的。但是你可以使用已经存在的类。std::pair<>非常适合表示两个值,而boost::touple<>则非常适合表示一组值。 - Martin York
@Benoit:针对这个问题,使用boost::tie和@Martin York的建议。 - Alexandre C.
我认为你的意思是 std::pair,如果你不介意的话,我已经纠正了你的帖子。 - Alexandre C.
@Benoit:如果这些变量之间关系如此密切,那么或许它们应该被放在一个类中。这样它们就可以在类的构造函数中被初始化了。 - Steve M

9
在C++0x中,您可以像这样做:
int const c = []() -> int { 
    int r; 
    switch(42) { 
    case 3: 
        r = 1; break; 
    case 4: 
        r = 2; break; 
    default: 
        r = 23; 
    }; 
    return r; 
}();

5
不知道为什么,但它看起来像JavaScript... - Alexandre C.

1

如果您愿意在要查看变量const的代码周围提供一些{},那么至少有类似的东西。将以下内容放入宏中:

#define CONSTIFY(T, NAME)                  \
for (bool p00 = true; p00; p00=false)      \
for (T p000 = NAME; p00; p00=false)        \
for (T const NAME = p000; p00; p00=false)

这应该在C99和C++中都可以工作。从技术上讲,这不会使您的原始变量成为const,而是为相关范围创建一个具有相同内容的新变量。

请注意,在某些情况下(例如breakcontinue),这可能会改变控制流程。但只要将其包装在基本上是整个函数体的东西周围,这应该可以工作。


聪明,但这将来会带来很多痛苦... :D - Nim
@Nim:我同意,这个应该不应该留在代码中。但是为了快速检查一些遗留代码,看看是否有尝试更改变量的地方,这可能仍然有所帮助。 - Jens Gustedt
此外,如果复制构造函数(例如auto_ptr)存在问题,这可能导致数据丢失。 - Benoit
@Benoit,我现在太过于思考C语言了。对于问题中的int类型,这不应该有太大变化。但对于C++来说,确实需要访问复制构造函数。为什么这会导致数据丢失,我不明白。 - Jens Gustedt
auto_ptr 析构函数调用 delete[]。因此,如果意图是共享指针,则不应复制它,只有在指针所有者应该被转移时才复制。 - Benoit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接