声明参考并稍后初始化?


71

我有对的引用MyOjbect,但确切的对象取决于条件。所以我想做这样的事情:

MyObject& ref; 
if([condition]) 
  ref = MyObject([something]) 
else 
  ref = MyObject([something else]);

我现在无法执行此操作,因为编译器不允许我声明但不能初始化引用。我该怎么做才能实现自己的目标?


3
这将是临时的初始化吗?即使没有条件:MyObject& ref = MyObject([something]);,也无法使用,因为您无法将临时绑定到非常量左值引用。
GManNickG

@GManNickG:这也适用于Zaffy和suszterpatt答案吗?
qPCR4vir

@ qPCR4vir:是的。在某种程度上,这个问题仍然存在,只是不直接。
GManNickG

如果您正在寻找实际的解决方案,请向下滚动到stackoverflow.com/a/50909452/1021920
hellow

Answers:


46

您需要对其进行初始化。但是,如果您想有条件地对其进行初始化,则可以执行以下操作:

MyObject& ref = (condition) ? MyObject([something]) : MyObject([something else]);

6
我不能这样做,因为我实际上是在这些条件下做事。我在这里很困惑。在我看来,这是一个很常见的场景,为什么不允许使用?我的编码风格是否抗c ++?
user1861088

4
@ user1861088:“我之所以不能这样做,是因为我实际上是在这些条件下做事的。”那么,为什么不真正显示出您在尝试做的事情呢?
GManNickG

1
我的意思是,我在每个条件内执行多行代码,而不仅仅是调用一个返回值的函数。所以我不能使用?: 对?
user1861088

@ user1861088您不能初始化引用,然后再次测试条件并执行多行代码吗?引用一旦创建便无法更改。引用不能为空。这两件事使您无法执行在问题中发布的内容。
iheanyi 2014年

6
您可以考虑使用lambda。
sergiol 2015年

18

AFAIK不能通过参考来完成。您必须使用一个指针:

MyClass *ptr;

if (condition)
    ptr = &object;
else
    ptr = &other_object;

指针的作用类似于参考。只是不要忘记->用于会员访问。


5
您只需声明一个引用就MyClass &ref = *ptr好像您要将其转换为引用一样……
poizan42 '16

将其声明为指针不会解决rvalue是函数返回的情况
Mystic Odin

不,它不会起到类似的参考,因为它会被放在堆,它需要手动删除。
乔苏·格尼(JosuGoñi),

1
@JosuGoñi都不是真的。仅当我要分配内存(通过new)时。ptr指向在堆栈上分配的对象。
0x499602D2

@ 0x499602D2他必须使用new,除非他可以使用move构造函数。
乔苏·格尼(JosuGoñi),

17

你做不到 引用必须绑定到某物,您可能不喜欢它,但是它可以防止整个类的错误,因为如果您有一个引用,则始终可以假定它已绑定到某物,这与指针可以为空不同。

您的示例代码无论如何都将无法工作,因为您尝试将非常量引用绑定到临时对象,这是无效的。

无论如何,为什么需要它作为参考?一种解决方案是确保您的类型具有便宜的默认构造函数并可以有效地移动,然后执行以下操作:

MyObject obj; 
if([condition]) 
  obj = MyObject([something]) 
else 
  obj = MyObject([something else]);

否则,您必须将条件代码放入一个或多个函数中,或者:

const MyObject& ref = createObject([condition]);

要么

const MyObject& ref = [condition] ? doSomething() : doSomethingElse();

请注意,这两个版本都使用const引用,如果对象必须为非const,则可以将其绑定到临时引用,然后再次停止尝试使用引用:

MyObject obj = createObject([condition]);

由于返回值的优化,这可能与您尝试执行的操作一样有效


这应该是首选答案!
Ashley Duncan

12

在C ++中,没有初始化就不能声明引用。您必须初始化它。


1
我明白那个。那么,有什么建议吗?基本上,我需要比该条件更大范围的参考。
user1861088

@ user1861088在这种情况下,要么1.重新设计代码(首选),2.使用指针(不推荐)。

1
3.不使用引用,仅使用对象
Jonathan Wakely 2013年

@ user529758对于在类内部声明的引用变量是否正确?class test{ test(param o ):ref(o){}myobj& ref;}
RaGa__M

12

简短的答案:你不知道。

稍长一点的答案:做这样的事情:

MyObject& getObject()
{
    if([condition]) 
        return [something] 
    else 
        return [something else];
}

MyObject& ref = getObject();

关于引用的通常免责声明当然适用。


1
是的,我想到了这个,但是..我不得不做所有这些事情才能实现看似简单的目标:(
user1861088 2013年

为什么getObject()返回参考?它指的是什么?
Jonathan Wakely

&Jonathan:这属于“通常的免责声明”部分。;)
suszterpatt

1
@ user1861088您看似简单的目标是标准不允许的。它与参考的定义冲突。您不妨问一问,为什么不能简单地将岩石抛向空中而又不掉到地上。这很简单-扔石头就可以了。
iheanyi

11

我想做的是一个立即执行的lambda。

假设我们想要一个 const std :: string&到映射下的变量-如果映射不包含给定的键-我们想抛出。

int main()
{
  std::map<std::string, std::string> myMap = {{"key", "value"}};

  const std::string& strRef = [&]()->const std::string& {
    try {
      return myMap.at("key"); // map::at might throw out_of_range
    }
    catch (...) {
      // handle it somehow and/or rethrow.
    }
  }(); // <- here we immediately call just created lambda.
}

您还可以使用std :: invoke()使其更具可读性(自C ++ 17起)

int main()
{
  std::map<std::string, std::string> myMap = {{"key", "value"}};

  const std::string& strRef = std::invoke([&]()->const std::string& {
    try {
      return myMap.at("key"); // map::at might throw out_of_range
    }
    catch (...) {
      // handle it somehow and/or rethrow.
    }
  });
}

2
是。如果只有ppl会回答一个问题,而不是建议不要问这个问题。这可能是实际解决OP的最干净的即时方法。+1。人们应该更频繁地向下滚动。.哈哈
violet313

5
MyClass *ptr;

if (condition)
    ptr = &object;
else
    ptr = &other_object;

MyClass &ref = *ptr;

3
回答问题时,考虑写你写的代码的解释,这个答案绝对没有增加任何新来的老的问题。
2015年

1
这看起来非常类似于此答案中的代码。
Artjom B. 2015年

尽管缺少任何解释是很糟糕的,但这仍然是唯一不会引入任何额外内容或不会限制您使用三元运算符编写的内容的唯一答案……
poizan42 '16

1
@ArtjomB。该答案未MyClass &ref = *ptr; 在最后提出建议,这是此处避免在以后进行进一步取消引用的关键行,并在以下位置进行了评论:stackoverflow.com/a/62793754/895245
Ciro Santilli郝海东冠状病六四事件法轮功

0

if([condition])MyObject&ref = MyObject([something]); else MyObject&ref = MyObject([something]);


您能解释为什么这比公认的答案更好吗?
Simply Ged

2
这样就不能在if块范围之外使用ref。
John Gowers

0

我通常这样做(C ++ 11或更高版本):

std::shared_ptr<ObjType> pObj;
if(condition)
    pObj = std::make_shared<ObjType>(args_to_constructor_1);
else
    pObj = std::make_shared<ObjType>(args_to_constructor_2);

这很干净,并且允许使用具有(可能不同)构造的对象定义,这是您不能直接使用指针执行的操作,因为编译器会抱怨使用临时对象。


-2

您可以使用“ extern”关键字:第一次(假设在头文件中)您可以使用“ extern”关键字在声明之前声明变量。稍后(在源文件中),您重复声明而不使用“ extern”,并为其赋值。


4
您试图回答什么问题?
jww
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.