C++ 条件运算符从其参数的副本返回值

C++ 条件运算符从其参数的副本返回值,c++,conditional-operator,temporary-objects,C++,Conditional Operator,Temporary Objects,如果条件运算符c?x:y的两个返回参数不是同一类型,则在应用强制转换之前会进行复制。在保持简单可用性的同时,是否可以防止这种情况 我有以下内容(问题减少): 但它在条件运算符和null ptr中的行为非常糟糕: Fixed f =...; // just here to show the type of f, don't read too much into this ... bool condition = ...; char *s = condition ? nullptr : f; 制作

如果条件运算符
c?x:y
的两个返回参数不是同一类型,则在应用强制转换之前会进行复制。在保持简单可用性的同时,是否可以防止这种情况

我有以下内容(问题减少):

但它在条件运算符和null ptr中的行为非常糟糕:

Fixed f =...; // just here to show the type of f, don't read too much into this
...
bool condition = ...;
char *s = condition ? nullptr : f;
制作了f的副本,s现在指向堆栈上的一个值,该值很快就会消失。这一切都是因为
nullptr
的类型是
std::nullptr\u t
f
将通过转换到
char*
,但仅在首先复制它之后。这似乎是非常糟糕的行为,但这是规范所说的

我目前的解决方案是使强制转换和ctor
显式化
,但这会稍微破坏可用性。还有其他解决办法吗

下面是一些示例代码(忽略质量,因为我正在大量使用它,以了解gcc和LLVM如何以不同方式处理此问题):

#包括
#包括
#包括
#包括
使用名称空间std;
结构A:公共数组{

A(){cerr您的问题是三元操作数的类型为
std::nullptr\u t
struct Fixed
。推理规则查找从一种操作数类型到另一种操作数类型的转换以及公共基类。没有机会推断
char*


您可以通过提供
操作符std::nullptr_t()=delete

自动捕捉错误
cond?nullptr:(char*)f
工作正常。
cond?(char*)nullptr:f
在LLVM中工作正常,但GCC拒绝编译(并且我将
修复(char*)
@JohnKugelman是的,基本上。我只是在那里显示
f
的类型。结构是从散列中检索的,因此我试图在散列中返回结构的
char*
,而不是返回堆栈上结构副本的
char*
。使用
somefunc(a&v)
那么
&v
就不能是null ptr。请给出一个更好的例子或一个更好的设计。@Ripi2:令人惊讶的是,这不是真的。你可以做
somefunc(*(a*)nullptr)
,只要不做从左值到右值的转换,这是合法的。@BenVoigt让我惊讶,是的。无论如何,我认为OP想要使用
char*x=somefunc(someinstance)
其中
someinstance
不是指针,而是类实例。但它似乎推断出
char*
。它甚至调用了正确的
操作符char*
方法。这只是一种奇怪的需要,需要先创建一个临时对象(以及GCC要求
修复(char*)的奇怪行为)
ctor,但不实际使用它)。@JasonN:它不推断
char*
,三元计算结果是一个
struct-Fixed
临时对象。然后
运算符char*()
char*
变量初始化期间被调用。您可以通过在变量之间引入一个
auto
类型的变量来证明这一点,比如
auto t=condition?nullptr:f;我是否认为三元,必须从两个分支返回相同的类型,在这种情况下,它需要在ternar之前进行推断y(即,我不能返回
A
,除非if可以从
nullptr
转换为
A
)…我刚刚用
auto
进行了测试,并强制一个编译器错误来查看类型。三元组返回一个
a
,这也意味着有一个从
nullptr
a
的隐式转换可能?我不明白这是怎么可能的?如果比较是真的,那就更糟糕了,
nullptr
被转换成一个A,它在没有编译器警告的情况下会出现故障。为什么它甚至可以将nullptr__t转换成任何非指针类型呢?再多玩一点,我就可以让编译器承认它可以从
nullptr___t
转换成
A
和/反之亦然/。很难看,但我想它不会比其他C更糟糕++丑陋。Shrugd你认为这是一个需要
a(char*)
来编译的GCC错误,不像LLVM,而且从不使用它吗?我应该报告它吗?
Fixed f =...; // just here to show the type of f, don't read too much into this
...
bool condition = ...;
char *s = condition ? nullptr : f;
#include <cstdio>
#include <iostream>
#include <array>
#include <cstring>

using namespace std;

struct A : public array<char,4> {
  A() { cerr<<"def\n"; }
  A(const A &o) { cerr<<"copy\n"; (*this)=o;}
  A(const char *s) { cerr<<"ctor\n";assign(s); } // explicit fixes
  void assign(const char*s) {cerr<<"assign\n";memset(this->begin(), 0, 4); strncpy(this->begin(), s, 4); }
  operator char*() { cerr<<"cast\n";return this->begin(); }
  //operator void*() { cerr<<"void\n";return this->begin(); }
  //operator std::nullptr_t() { cerr<<"void\n";return (std::nullptr_t)this->begin(); }
};

volatile A *faraway = new A();

char* plain(A &v) { cerr<<"in pl\n";
  return faraway == nullptr ? nullptr : v;
}
char* cast1(A &v) { cerr<<"in c1\n";
  return faraway == nullptr ? (char*)nullptr : v;
}
char* cast2(A &v) { cerr<<"in c2\n";
  return faraway == nullptr ? nullptr : (char*)v;
}

int main() {
  A *a = new A; a->assign("asd");

  char *x = a->data();
  cerr << "\nplain\n";
  char *yp = plain(*a);
  cerr << "\nc1\n";
  char *y1 = cast1(*a);
  cerr << "\nc2\n";
  char *y2 = cast2(*a);

  cerr << "\n---\n";
  cerr << (void*)a << "\n" << (void*)(a->data()) << "\n" << (void*)x << "\n---\n";
  cerr << (void*)yp << "\n" << (void*)y1 << "\n" << (void*)y2 << "\n";

  return 0;
}