【问题标题】:Can I avoid explicitly writing a constructor for each struct in a std::variant?我可以避免为 std::variant 中的每个结构显式编写构造函数吗?
【发布时间】:2018-03-14 09:49:13
【问题描述】:

考虑这段代码:

#include <variant>

struct x {
  int y;
};

int main() {
  std::variant<x> v(std::in_place_type<x>, {3}); /*1*/
  return std::get<x>(v).y;
}

这不会编译,从/*1*/ 行中删除{} 时也不会编译,即使聚合初始化也是如此

x a{3};
x b({3});

以“类构造函数”形式工作。我能否以某种方式让std::variant 初始化程序意识到使用聚合初始化构造结构的可能性,而不必为可能在我的实际案例中使用的每个结构编写无聊的样板构造函数?

我希望这能以某种方式工作,正如cppreference 所讨论的两个重载 (5) 和 (6) 都说的那样

使用指定的替代 T 构造一个变体,并使用参数 [...]

初始化包含的值

如果这很重要,我正在使用 GCC 7。

【问题讨论】:

  • 如果它安慰你,std::make_unique 和家人有同样的限制:(
  • 聚合初始化一直是C++初始化系统的眼中钉

标签: c++ c++17 variant aggregate-initialization


【解决方案1】:

也许这不是您要问的,但是显式构造对象而不是依赖类型推断呢?

#include <variant>

struct x {
  int y;
};

int main() {
  std::variant<x> v(std::in_place_type<x>, x{3});
  return std::get<x>(v).y;
}

【讨论】:

  • 其实我会很高兴的!根据标题,我的问题是关于避免构造函数,这是实现的。从技术上讲,它会涉及一些移动,但在简单的情况下,优化器会在没有开销的情况下处理这些。
  • 确实,如果你的类提供了一个移动的构造函数,那就很简单了。由于您不想要任何显式定义的构造函数,因此您应该保证隐式移动构造函数(或至少默认一个)。
【解决方案2】:

除了添加构造函数之外,没有其他解决方法。对于您提到的两种重载,标准都要求这样做,[variant.ctor]19 和 [variant.ctor]23 分别为:

效果:初始化包含的值,就像使用参数 std​::​forward&lt;Args&gt;(args)... 直接非列表初始化 T 类型的对象一样。

效果:初始化包含的值,就像使用参数 il, std​::​forward&lt;Args&gt;(args)... 直接非列表初始化 T 类型的对象一样。

您始终可以使用以下方法复制或移动对象:

std::variant<x> v(std::in_place_type<x>, x{3});
// or more clear and does the same thing
std::variant<x> v(x{3});

【讨论】:

    【解决方案3】:

    如果你想矫枉过正,我们可以创建一个具有转换运算符的工厂类型:

    template <class... Args>
    struct list_init_from {
        std::tuple<Args...> args;
    
        template <class T>
        operator T() {
            return std::apply([](auto... args){
                return T{args...};
            }, args);
        }   
    };
    
    template <class... Args>
    list_init_from(Args... ) -> list_init_from<Args...>;
    

    你可以使用的:

    std::variant<x> v(std::in_place_type<x>, list_init_from{3});
    

    这可行,但仍有很多不足之处:完美的转发、转换运算符上的 SFINAE 以及明确指定允许转换的类型是留给读者的练习。

    【讨论】:

      猜你喜欢
      • 2021-07-03
      • 1970-01-01
      • 1970-01-01
      • 2022-07-20
      • 2023-02-20
      • 2014-04-15
      • 2012-06-05
      • 1970-01-01
      相关资源
      最近更新 更多