`a?b:c` 的操作数可以有不同的类型吗?最好的选择是什么?

Vor*_*rac 3 c++ if-statement initialization c++20

#include <iostream>
#include <string>


struct Base
{
    Base(int)
    {
        std::cout << "int\n";
    }

    Base(std::string)
    {
        std::cout << "string\n";
    }
};


struct S : Base
{
    S(bool b)
    : Base{ b ? int{} : std::string{} }
    {}
};


int main()
{
    S(42);
    S("fortytwo");
}
Run Code Online (Sandbox Code Playgroud)

这段代码有几个编译错误,但更有趣的是

?: 的操作数有不同的类型:int 和 std::string。

约束:

  • Base ctor 初始化常量,所以我不能使用 ctor 主体。
  • 这是唯一一个具有bool魔力的派生类,因此更改Base以适应它是......不可取的。

现在怎么办?这段代码的重点是派生类S调用Base基于 a的重载构造函数之一bool

考虑的解决方案:

  • 一个IIFE能够工作,但相当难看且长。
  • 辅助函数 - 相同。
  • 模板 S 并传递到b那里 - 我需要一个运行时决定。

编辑:@Yakk - Adam Nevraumont的回答对原始问题来说非常棒。

但我错过了一个关键的细节。Base是抽象的,即添加virtual void foo() = 0;到它的定义中。所以它不能被实例化。

Yak*_*ont 6

S(bool b):
  Base{ b ? Base{int{}} : Base{std::string{}} }
{}
Run Code Online (Sandbox Code Playgroud)

活生生的例子

你可以变得更狂热:

S(bool b):
  Base{ [&]()->Base{
    if (b)
      return int{};
    else
      return std::string{};
  }() }
{}
Run Code Online (Sandbox Code Playgroud)

活生生的例子

在第一个示例中,移动完成;在第二种情况下,保证省略意味着只Base创建一个对象。您可以通过添加以下内容来测试:

Base(Base&&)=delete;
Run Code Online (Sandbox Code Playgroud)