在C++中为什么不能使用static_cast<int&>将整数引用参数传递给函数?

10
我在一个C++程序中有一个枚举参数,我需要使用一个通过参数返回值的函数来获取它。一开始我把它声明为int类型,但是在代码审查时被要求将其类型更改为枚举(ControlSource)。我这样做了,但它破坏了Get()函数——我注意到使用C风格的int&转换可以解决问题,但当我尝试使用static_cast<>修复它时,它无法编译。
为什么会这样呢?而当eTimeSource是int类型时,根本不需要进行任何转换就可以通过引用传递整数?
//GetCuePropertyValue signature is (int cueId, int propertyId, int& value);

ControlSource eTimeSource = ControlSource::NoSource;

pPlayback->GetCuePropertyValue(programmerIds.cueId, DEF_PLAYBACKCUEPROPERTY_DELAY_SOURCE, static_cast<int&>(eTimeSource)); //This doesn't work.

pPlayback->GetCuePropertyValue(programmerIds.cueId, DEF_PLAYBACKCUEPROPERTY_DELAY_SOURCE, (int&)(eTimeSource)); //This does work.

int nTimeSource = 0;
pPlayback->GetCuePropertyValue(blah, blah, nTimeSource); //Works, but no (int&) needed... why?

可以工作,但不需要(int&)...为什么?请查看有关通过引用传递变量的C++文档(或参见此处:https://dev59.com/i3RC5IYBdhLWcg3wFdJx#410857) - Mihai Todor
我猜测C风格的转换是在这个对象上调用reinterpret_cast使其工作,我的猜测正确吗?如果是这样,对于一个基于int类型的枚举来说,这真的很重要吗? - Gareth
不,reinterpret_cast与C语言风格的“大锤式”转换也不同。如果您需要一个丑陋的hacky转换来使代码在更改类型后正常工作,请不要更改类型!这可以在int中正常工作,但它不能在枚举中正常工作…… 对我来说答案似乎很清楚。 - Jonathan Wakely
2个回答

8

当您将变量转换为不同类型的值时,您会获得一个临时值,该值无法绑定到非常量引用:修改临时值没有意义。

如果您只需要读取该值,则可以使用常量引用:

static_cast<int const &>(eTimeSource)

但是你可以创建一个实际的值,而不是一个引用:

static_cast<int>(eTimeSource)

在 static_cast<int const &>(eTimeSource) 的情况下,编译器告诉我它找不到一个合适的函数重载,static_cast<int>(eTimeSource) 也是同样的情况。我不想更新 GetProperty 函数以接受一个 const 引用,因为我怀疑这将涉及到在其他地方进行大量更改。 - Gareth
1
@Gareth:那么创建一个本地变量,int i = static_cast<int>(eTimeSource); 并使用 i 调用该函数。 - Kerrek SB
好的 - 那显然可以工作。但是这有点循环,因为我一开始就将变量声明为int,没有任何转换,但是审阅者不喜欢!我理解他的观点 - 正确声明类型可以清楚地说明它的用途,但这也带来了这个问题... - Gareth
@Gareth:这就是你为遗留代码所付出的代价。正确的做法是更改接口以直接接受枚举,但如果你无法这样做,那么你必须绕过它。你可以向审核人提出此问题。 - Kerrek SB

3
static_cast<int&>((eTimeSource))); //This doesn't work.

没错,它无法工作,因为eTimeSource不是一个int,所以你不能将一个int&绑定到它上面。

(int&)((eTimeSource))); //This does work.

错误,那也行不通,它只是看起来可以。C样式转换欺骗编译器并说:“即使这不合法,也将其设置为该类型”。仅因为某些内容可以编译,并不意味着它会起作用。

为什么当 eTimeSource 是一个 int 时根本不需要强制转换就可以通过引用传递整数?

因为您可以将 int& 绑定到 int,但不能绑定到其他类型,而 eTimeSource 是另一种类型。 int& 是对 int 的引用。如果您能将其绑定到其他类型,它不会指向一个 int,不是吗?

如果代码评审员要求将变量更改为枚举类型,则可能还意味着您需要将函数参数更改为使用 ControlSource&


如果ControlSource实际上是一个enum class,那该怎么办?根据OP的代码,这似乎是一个选项。 - Daniel Frey
@DanielFrey,这会改变我的回答吗?(说实话,我只是简要地重新阅读了一下,所以如果有的话请纠正它) - Jonathan Wakely
嗯,在这种情况下,实际上它并没有改变任何东西。抱歉,我读得太匆忙了 :-/ - Daniel Frey
1
“仅仅因为它编译通过,并不意味着它能正常工作。”出于好奇,这样做真的有效吗?在 int 和基于 int 的枚举之间使用 C 风格的强制转换是否存在任何风险? - Gareth
3
“work” 的意思是什么?我认为 (int&)(eTimeSource) 等同于 const_cast<int&>(static_cast<const int&>((int)eTimeSource)),这将创建一个临时整数,并将一个 const 引用绑定到它上面,然后转换掉 const。如果函数修改参数(我认为它会这样做,因为它接受的是非 const 引用),那么它将修改临时变量,而不会更改 eTimeSource……所以您会失去设置的值。我怀疑这是否符合正确工作的要求。 - Jonathan Wakely
显示剩余2条评论

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