我可以避免为 std::variant 中的每个结构显式编写构造函数吗?

Can I avoid explicitly writing a constructor for each struct in a std::variant?

考虑这段代码:

#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});

在两种 "constructor-like" 形式中都有效。我能否以某种方式让 std::variant 初始化程序意识到使用聚合初始化构造结构的可能性,而不必为可能在我的真实案例中使用的每个结构编写无聊的样板构造函数?

我希望它能以某种方式工作,根据 cppreference 两个重载 (5) 和 (6) 都说

Constructs a variant with the specified alternative T and initializes the contained value with the arguments [...]

如果重要的话,我正在使用 GCC 7。

也许这并不完全是您要问的,但是显式构造对象而不是依赖类型推断怎么样?

#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;
}

除了添加构造函数外,没有解决此问题的方法。对于您提到的两个重载,标准分别要求 [variant.ctor]19 and [variant.ctor]23

Effects: Initializes the contained value as if direct-non-list-initializing an object of type T with the arguments std​::​forward<Args>(args)....

Effects: Initializes the contained value as if direct-non-list-initializing an object of type T with the arguments il, std​::​forward<Args>(args)....

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

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});

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

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 以及明确指定允许转换的类型是留给 reader.

的练习