85

我有一些类的引用MyObject,但确切的对象取决于条件。我想做这样的事情:

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

我现在不能这样做,因为编译器不允许我声明但不能初始化引用。我能做些什么来实现我的目标?

4

12 回答 12

59

你需要初始化它。但是如果你想有条件地初始化它,你可以这样做:

MyObject& ref = (condition) ? MyObject([something]) : MyObject([something else]);
于 2013-02-14T20:03:05.497 回答
22

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

MyClass *ptr;

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

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

于 2013-02-14T22:15:07.803 回答
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引用,它可以绑定到临时对象,如果对象必须是非常量,则再次停止尝试使用引用:

MyObject obj = createObject([condition]);

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

于 2013-02-14T20:30:24.267 回答
17

我喜欢做的是立即执行的 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.
    }
  });
}
于 2018-06-18T12:23:37.890 回答
12

在 C++ 中,您不能在没有初始化的情况下声明引用。您必须对其进行初始化。

于 2013-02-14T20:00:00.940 回答
12

简短的回答:你没有。

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

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

MyObject& ref = getObject();

当然,关于参考的通常免责声明也适用。

于 2013-02-14T20:12:03.477 回答
5
MyClass *ptr;

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

MyClass &ref = *ptr;
于 2015-03-27T22:59:43.143 回答
1

使用静态假人作为占位符。或 std::optional 与 reference_wrapper。

static X placeHolder_;
std::reference_wrapper<X> ref = placeHolder_;
   


std::optional<std::reference_wrapper<X>> ref ;    
于 2022-02-24T03:01:35.837 回答
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);

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

于 2020-11-01T17:45:54.220 回答
-1

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

于 2019-05-13T22:49:07.977 回答
-2

您可以使用在实际使用之前不需要初始化的模板。

  template <uint8_t c>
  uint8_t& ref; 
void setup()
{
  uint8_t a=1;
  uint8_t b=2;
if(true) 
  ref<1> = a;
else 
  ref<1> = b;
}

一些旧的 IDE 可能会将其标记为错误,但它会很好地通过编译。

于 2021-06-25T09:39:18.133 回答
-3

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

于 2017-04-21T14:37:48.483 回答