三元条件运算符 `?:` 的结果类型表达

4

以下函数应该像 ?: 一样工作,但没有惰性。你会将返回类型指定为什么?

我的第一次尝试如下:

template <typename T1, typename T2>
T1 myif(bool b, T1&& true_result, T2&& false_result)
{
    if (b) {
        return true_result;
    } else {
        return false_result;
    }
}

但后来我发现了一个名为 "given" 的东西:
int f() { return 42; }
int x = 5;

虽然
(true ? x : f())++; 

无法编译,

myif(true, x, f())++;

编译正常但返回悬空引用。

我的第二次尝试是将返回类型更改为:

typename std::remove_reference<T1>::type

但随后...
(true ? x : x)++

可以工作,但是:

myif(true, x, x)++

现在我返回的是值,而不是引用。

即使:

auto myif(bool b, T1&& true_result, T2&& false_result) 
  -> typeof(b ? true_result : false_result)

失败了,我不确定为什么,也许是因为typeof将其参数转换为值类型。无论如何,重点是要明确地表达类型,而不是通过autotypeof

有没有想法如何编写一个返回与?:相同类型的函数?


6
std::common_type 是一个类型转换工具,但它不能保留值类别,因为结果会被 std::decay 处理。另外,在 C++11 中正确的拼写是 decltype,而不是 typeof - T.C.
3
为什么不使用decltype(b ? std::forward<T1>(true_result) : std::forward<T2>(false_result)) - Casey
无论如何,?: 的规则占据了标准的1.5页。其中的一些部分需要知道 AFAIK 不可能通过编程确定的东西(例如,一个表达式是否可以转换为 T&T && 受到引用必须直接绑定的限制);而其他部分虽然可能实现,但是没有 decltype 非常繁琐(例如,通常的算术转换)。 - T.C.
如果需要 C++03 兼容性,你可能想要查阅这个链接:https://dev59.com/7UzSa4cB1Zd3GeqPnIGx#2450157。 - Johannes Schaub - litb
1个回答

1

我相信最好的方法是Casey提出的:

template <typename T1, typename T2> 
auto myif(bool b, T1&& true_result, T2&& false_result)
    -> decltype(b ? std::forward<T1>(true_result) : std::forward<T2>(false_result))
{
    if (b) {
        return true_result;
    } else {
        return false_result;
    }   
}

在C++14中,这只需要:

template <typename T1, typename T2> 
decltype(auto) myif(bool b, T1&& true_result, T2&& false_result)
{
    // same body
}

鉴于以下内容:
int f() { return 42; }
int x = 5, y = 7;

myif(true, x, f())++; // error: lvalue required as increment operand
myif(false, x, y)++;  // OK

如果类型不同,它是否会编译通过?bool 不是编译时常量,因此除非它们最初就是相同的类型,否则编译器如何知道结果应该是什么类型...? - user673679
@user673679 当然可以。只要有一个公共类型(例如,你不能像 b ? "hello" : 4.2 这样做)。请参阅参考文献以获取更详细的解释。 - Barry
谢谢。我想我以前没有像那样考虑过三元运算符。 - user673679
你的C++14版本存在问题。"如果具有占位符类型的声明返回类型的函数具有多个返回语句,则为每个返回语句推断返回类型。如果在每个推断中推断的类型不相同,则程序无法形成。" - Ben Voigt
如果类型相同,则两个版本都无法正常工作。 如果T1T2都是int,则在C++11版本中,返回类型声明为int &&。 在C++14版本中,decltype(auto)会导致返回类型被推断为int &&。 无论哪种方式,true_resultfalse_result都是lvalue,不能绑定到rvalue引用。 - user743382

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