标签: std-variant

如何获得变体值的引用?

std::variant所有类都来自同一个基地.我想将变体转换为基础.

return std::visit( []( const Base& b ) { return b; }, v );
Run Code Online (Sandbox Code Playgroud)

这编译但发出警告C4172:返回本地变量的地址或临时

有没有办法访问std::variant到位,而无需制作本地或临时副本?

或者,如果这是不可能的,我怎样才能将值转换为void*可以使用static_cast

更新:我认为这个例子应该是显而易见的,但事实并非如此,这是完整的复制品:

#include <variant>

struct Base {};
struct A : Base {};
struct B : Base {};

const Base& cast( const std::variant<A, B>& v )
{
    return std::visit( []( Base const& b ) { return b; }, v );
}

int main()
{
    std::variant<A, B> v{ A{} };
    const auto& b = cast( v ); …
Run Code Online (Sandbox Code Playgroud)

c++ visual-c++ std-variant

2
推荐指数
1
解决办法
126
查看次数

std::visit 带有重载自由函数而不是函数对象的 std::variant

在 C++17 中,是否有一种简单的方法来 std::visit 带有重载自由函数的变体,或者我必须使用带有重载调用运算符的对象?

换句话说,是否可以添加一些简单的东西来使以下//ERROR!行编译为与该//OK!行在功能上相同?

#include<variant>
#include<iostream>
#include<list>

#include <boost/hana/functional/overload.hpp>
using boost::hana::overload;

struct A {};
struct B {};

void foo(A) { std::cout << "Got an A!\n"; }
void foo(B) { std::cout << "Got a  B!\n"; }

using AorB = std::variant<A,B>;

constexpr auto foo_obj = overload(
    [](A){std::cout << "Got an A!\n";},
    [](B){std::cout << "Got a  B!\n";});

int main() {

  std::list<AorB> list{A(), B(), A(), A(), B()};

  for (auto& each : list) std::visit(foo, each);      // ERROR!
  for (auto& …
Run Code Online (Sandbox Code Playgroud)

c++ non-member-functions c++17 stdapply std-variant

2
推荐指数
1
解决办法
846
查看次数

如何使 std::variants 的使用在语法上更加“可口”?

这是受到我给新手用户的回答的启发,我建议他们使用 anstd::variant而不是 union。

通过工会,您可能会遇到如下情况:

struct Box {
    struct Item { float value; };
    using Boxes = std::vector<Box>;

    union Value {
        Item item;
        Boxes boxes;
    };

    Value contents;
    std::string label;
};
Run Code Online (Sandbox Code Playgroud)

(不完全是最初的问题,我在这里接受了一些诗意的许可。)并且使用一个变体,该类可能如下所示:

struct Box {
    struct Item { float value; };
    using Boxes = std::vector<Box>;

    std::variant<Item, Boxes> contents;
    std::string label;
};
Run Code Online (Sandbox Code Playgroud)

问题是,使用第一个变体,我可以写

if (box.contents.boxes.size() > 2) { foo(); }
Run Code Online (Sandbox Code Playgroud)

如果我已经确定会有子框,这就会起作用。

对于std::variant,我必须写:

if (std::get<Boxes>(box.contents).size() > 2) { foo(); }
Run Code Online (Sandbox Code Playgroud)

我觉得第二个版本的可读性要差得多,有点混乱,而且很分散注意力。另外 - 我必须知道 的类型boxes

在我的代码中,我可以做些什么来让我的用户无需进行此类std::get()调用,并使他们的生活更加愉快?

c++ idioms syntactic-sugar c++17 std-variant

2
推荐指数
1
解决办法
683
查看次数

如何在 std::variant 的向量中过滤掉某些数据类型的元素?

我有一个类型为或std::vectorstd::variant元素。如果迭代元素的类型为 ,我想遍历这个向量和一个额外的项目。但是,似乎不允许在运行时查询索引。我怎样才能做到这一点?intstd::set<int>insertstd::set<int>

#include <variant>
#include <set>
#include <vector>

int main()
{
    using Variants = std::variant<int, std::set<int>>;

    std::vector<Variants> var_vec;
    var_vec.push_back(999);
    std::set<int> a = {0,1,2};
    var_vec.push_back(a);

    for (int i = 0; i < var_vec.size(); ++i)
    {
        // if the element var_vec[i] is of type std::set<int>
        if (var_vec[i].index() == 1) var_vec[i].insert(888);   // !ERROR! How to achieve this?
    }
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

错误信息:

error: '__gnu_cxx::__alloc_traits<std::allocator<std::variant<int, std::set<int, std::less<int>, std::allocator<int> > > >, std::variant<int, std::set<int, std::less<int>, std::allocator<int> > …
Run Code Online (Sandbox Code Playgroud)

c++ stdvector stdset c++17 std-variant

2
推荐指数
1
解决办法
82
查看次数

使用传递的 lambda 调用 std::visit

我有一个包含variant.

我想为该结构编写一个成员函数,该函数应该根据当前持有的类型变体运行代码。

但是,我在编译时遇到问题。我不想使用更多的“模板恶作剧”,比如使用单独的结构来定义operator(T&),因为它会进一步污染语法。这是一个例子:

struct Data {

std::variant<int, double> var;


//Into this function,multiple lambdas should be passed for cases that the user wants to handle
template<typename ... Funcs>
void apply(Funcs&&... funcs) {
    std::visit(std::forward<Funcs>(funcs)...,var);
}
};
int main() {
    Data d;
    d.var = 4;
    //variant holds int and lambda provided that takes int&, execute it:
    d.apply([](int& i){
        std::cout << "I am Int Poggers" << std::endl;
    });
    d.var = 0.0;
    //variant holds double but no lambda passed that takes …
Run Code Online (Sandbox Code Playgroud)

c++ c++17 std-variant

2
推荐指数
1
解决办法
1834
查看次数

“增量”`std::variant` 替代方案

我想增加/减少 astd::variant的类型替代,基本上像这样:

using var_t = std::variant</*...*/>;
var_t var;
var.emplace< (var.index()+1) % std::variant_size<var_t> >(); // "increment" case, wrapping for good measure
Run Code Online (Sandbox Code Playgroud)

这里的问题是,虽然emplace期望 clang 的错误消息称为“显式指定的参数”,index但似乎不是constexpr.

明显的替代方案是这样的:

switch(var.index()){
  0:
    var.emplace<1>();
    break;
  1:
    var.emplace<2>();
    break;
// ...
  variant_size<var_t>-1:
    var.emplace<0>();
}
Run Code Online (Sandbox Code Playgroud)

但这就是我个人所说的“极其丑陋”和“维护背后的巨大痛苦”(特别是因为我必须维护这些块的两个几乎副本,以进行递增和递减)。

有没有更好/“正确”的方法来做到这一点?

如果该信息在任何方面都很重要,我的目标C++20是.clanglibstdc++

c++ c++20 std-variant

2
推荐指数
2
解决办法
383
查看次数

使用 std::enable_if 重载函数以避免模板替换错误

我想编写两个模板函数,一个捕获特定情况,另一个捕获与第一个情况不匹配的所有其他情况。我尝试使用 std::enable_if 来捕获特定情况,但编译器仍然因不明确的匹配而失败。如何编写这些重载函数以便编译器解决歧义?(我使用的是g++)

我尝试编写以下代码(这是重现问题的简化示例):

struct resource1_t{
};

struct resource2_t{
};

template <typename R, typename V>
struct unit_t{
  typedef R resource_t;
  typedef V value_t;
  unit_t(value_t const& value):v(){}
  value_t v;
  value_t calcValue(resource_t const& r)const{return v;}
};

// Specific case (U::resource_t == R)
template <typename U, typename R, typename=std::enable_if_t<std::is_same_v<typename U::resource_t,R>>>
      typename U::value_t callCalcValue(U const& u, R const& r){
        return u.calcValue(r);
      }

 // General case (U::resource_t != R)
 template <typename U, typename R>
      typename U::value_t callCalcValue(U const& u, R const& r){
        // Fail immediately! …
Run Code Online (Sandbox Code Playgroud)

c++ enable-if c++17 std-variant

1
推荐指数
1
解决办法
1091
查看次数

通过网络、跨平台传递 std::variant 是否安全

std::variant 是 union 的替代品。

但union可以通过网络安全地在另一个平台(不同的编译器或arch)接收。std::variant 可以这样做吗?

比如我有两台机器A和B。A是windows,MSVC 19.4。B 是 Linux、gcc(或其他编译器,例如 MSVC 17)。我在A(或B)下编译代码:

std::variant<int, double> v = 1; // holds int.
f.write(&v, sizeof(v));
Run Code Online (Sandbox Code Playgroud)

B 可以使用以下代码从同一文件中读取正确的值吗?

std::variant<int, double> v;
f.read(&v, sizeof(v));
Run Code Online (Sandbox Code Playgroud)

如果 std::variant 无法安全地通过网络传递。有图书馆提供吗?增强::变体?或者也许创建一个像 std::variant 一样的自定义实现?

c++ compatibility std-variant

1
推荐指数
1
解决办法
462
查看次数

如何使用访问者在 lambda 中调用 std::visit ,访问者是按值捕获的函数对象

似乎std::visit在 lambda 中使用访问者调用并不简单,访问者是由值捕获的函数对象。虽然通过引用捕获工作正常。为什么会这样,是否有可能做到这一点?

在这种情况下,我不明白来自 MSVC 2017 的编译错误消息:

std::visit': 找不到匹配的重载函数
未能专门化函数模板未知类型 std::visit(_Callable &&,_Variants &&...)

我认为模板参数推导的行为与仅在std::visit没有包装调用的 lambda 的情况下进行调用非常相似。

说明问题的代码:

#include <variant>

struct T {
    void operator()(int i) {};
    void operator()(float f) {};
};

int main()
{
    std::variant<int, float> v = 1;
    T t;

    // Does not compile.
    //auto l1 = [t](auto v) { std::visit(t, v); };
    //l1(v);

    // Compiles.
    auto l2 = [&t](auto v) { std::visit(t, v); };
    l2(v);

    // Compiles.
    std::visit(t, v);

}
Run Code Online (Sandbox Code Playgroud)

c++ lambda generic-lambda c++17 std-variant

1
推荐指数
1
解决办法
353
查看次数

默认构造 std::variant 中的所有类型并将它们放入 std::vector

我将如何制作std::vector包含a中包含的所有类型的默认构造实例的 a std::variant

using TaskVariant = std::variant<TypeA, TypeB, TypeC>;
std::vector<TaskVariant> variants;

// I'd like to do this in a loop
variants.push_back(TypeA());
variants.push_back(TypeB());
variants.push_back(TypeC());
Run Code Online (Sandbox Code Playgroud)

c++ templates template-meta-programming c++17 std-variant

1
推荐指数
1
解决办法
250
查看次数

如何简化 std::variant 类类型

我确信有一种简单的方法可以做到这一点,但在 SO 中找不到任何东西。在en.cppreference.com 中也找不到太多信息。

有没有办法简化 ,std::variant</*class types*/>以便我们可以声明可以std::variant作为参数的函数和类。

考虑这个例子:

我有一个向量,它充当以下内容的容器std::variant

std::vector<std::variant<Car, Space, Human>> EntityContainer;
Run Code Online (Sandbox Code Playgroud)

如果我想将此向量作为参数传递给函数,则必须添加以下参数声明。

void Function(std::vector <std::variant<Car, Space, Human>>& container);
Run Code Online (Sandbox Code Playgroud)

我也许可以在这个例子中使用,但这并不能真正解决问题。

有没有更好的解决方案,而不是std::variant在项目的任何地方一遍又一遍地列出相同的类类型?

代码直播

#include <iostream>
#include <vector>
#include <variant>


class Human
{
public:
  void Talk(){ std::cout << "whass up\n"; }
};
class Car
{
public:
  void RunEngine() { std::cout << "Vroom\n"; }
};
class Space
{
public:
  void Expand() { std::cout << "Expand slowly\n"; }
};

struct VisitPackage …
Run Code Online (Sandbox Code Playgroud)

c++ variant c++17 std-variant

0
推荐指数
1
解决办法
1637
查看次数

是否可以选择创建包含具有不同返回类型的函数的向量?

我有以下向量

std::vector<std::pair<std::string, std::function<std::string(const PlayerFRDb&)>>> stringExtractors = {
    {" TEAM ", extractTeam},
    {" NAME ", extractName},
    {" TYPE ", extractProperty4},
};

std::vector<std::pair<std::string, std::function<int(const PlayerFRDb&)>>> intExtractors = {
    {" WS ", extractProperty0},
    {" LS ", extractProperty1},
    {" W ", extractProperty2},
    {" L ", extractProperty3},
};

std::vector<std::pair<std::string, std::function<char(const PlayerFRDb&)>>> charExtractors = {
    {" WAY ", extractProperty5},
};

std::vector<std::pair<std::string, std::function<double(const PlayerFRDb&)>>> doubleExtractors = {
    {" LINE ", extractProperty6},
};
Run Code Online (Sandbox Code Playgroud)

为了更容易地使用这些函数,我想将它们集中到一个向量中,但问题是它们返回不同的类型。

我尝试使用 std::variant,但无法初始化向量,因为编译器打印出:“没有构造函数的实例与参数列表参数类型匹配 ({...}, {...}, {. ..}、{...}、{...}、{...}、{...}、{...}) "

using FuncVariant = std::variant<
    std::function<std::string(const PlayerFRDb&)>, …
Run Code Online (Sandbox Code Playgroud)

c++ vector std-variant

-1
推荐指数
1
解决办法
146
查看次数