c++ std::使用整数数组中的元素作为std::variant中的目标类型,从std::variant获取内容

arknldoa  于 2023-02-10  发布在  其他
关注(0)|答案(6)|浏览(208)

我有一个整数数组来检索std::variant中的内容。但是它编译失败,错误消息No matching function to call 'get'。你能解释一下为什么,并建议工作解决方案来达到同样的目的吗?

using my_type = std::variant<int, float, bool>;
constexpr int[] expected_types = {2,2,2,2};
 

bool validate(std::vector<my_type> input) {
  bool rst;
  if (input.size() != 4) {
    return false;
  }
  for (int i = 0; i < 4; i++) {
    rst = rst || std::get<my_type[i]>(input[i]);
  }
  return rst;
}

下面是更多的上下文。类A、B、C都实现了接口bool foo(std::vector<my_type> input)。但是类A的输入是{int,int,bool}格式,类B的输入是{int,int,float}格式,类C的输入是{bool,bool}格式。每个类中的expected_types将自己的类型保存在输入向量中。然后std::get〈expected_types[i]〉用于访问输入向量中的元素。您能建议一个清晰优雅的模式来适合我的情况吗?
非常感谢!

lb3vh1jj

lb3vh1jj1#

如果我正确理解了validate函数,它应该验证vector<variant<int, float, bool>> ...
1.具有ABC类型的正确长度。
1.包含由A::expected_types[]B::expected_types[]C::expected_types[]中的variant索引指示的variant类型。
然后,它可以将正在测试vector的类型(ABC)作为模板参数,并使用variant::index()来检查各个variantvector中持有的类型。
将它与&&上的一个fold(因为你希望所有的都是true)结合起来,你会得到:

template<class T>
bool validate(const std::vector<my_type>& input) {
    if (input.size() != std::size(T::expected_types))  return false;

    return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
        // fold over && :
        return (... && (input[Is].index() == T::expected_types[Is]));
    }(std::make_index_sequence<std::size(T::expected_types)>());
}

如果您“真的”想从vectorstd::getexpected_types,并使用逻辑OR,可以通过类似的方式完成,但要在||上折叠:

template <class T>
bool get_bool(const std::vector<my_type>& input) {
    if (not validate<T>(input)) return false; // use the validation function above

    return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
        // fold over ||
        return (... || (std::get<T::expected_types[Is]>(input[Is])));
    }(std::make_index_sequence<std::size(T::expected_types)>());
}

Demo

k5hmc34c

k5hmc34c2#

因为函数get需要类型或编译时常量作为索引,所以您的方法将不起作用。
为了达到你想要的,你需要修改你的函数,使它成为一个函数模板。
然后,在调用“validate”函数时,可以将bool的索引值作为编译时常量模板参数提交。
你的程序看起来就像这样:

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

using my_type = std::variant<int, float, bool>;
constexpr size_t intPart = 0;
constexpr size_t floatPart = 1;
constexpr size_t boolPart = 2;

template <std::size_t I>
bool validate(std::vector<my_type> input) {
    bool rst{};
    if (input.size() != 4) {
        return false;
    }
    for (int i = 0; i < 4; i++) {
        rst = rst || std::get<I>(input[i]);
    }
    return rst;
}
int main() {
    std::vector<my_type> boolData(4);
    boolData[0].emplace<boolPart>(false);
    boolData[1].emplace<boolPart>(false);
    boolData[2].emplace<boolPart>(true);
    boolData[3].emplace<boolPart>(false);

    bool result = validate<boolPart>(boolData);

    std::cout << "Result = " << std::boolalpha << result << '\n';
}

如果以后需要扩展validate函数来处理其他类型的std::variant,可以使用可变参数模板和constexpr if来实现
请反馈,如果这是解决方案是足够的你.

7xllpg7q

7xllpg7q3#

使用std::variant::index可以很好地实现目标:

template<typename T>
bool validate(std::vector<my_type> input, const T& expectedTypes)
{
    if (input.size() != std::size(expectedTypes)) {
        return false;
    }
    bool rst = true;
    auto it = std::begin(input);
    for (auto expectedType : expectedTypes) {
        rst = rst && (it->index() == expectedType);
        ++it;
    }
    return rst;
}

https://godbolt.org/z/G9aMfWfEn

alen0pnh

alen0pnh4#

my_type不是一个数组,所以my_type[i]没有意义。
我猜std::get<my_type[i]>(input[i])应该是std::get<expected_types[i]>(input[i])?这也不起作用,因为i不是编译时常量,所以不能用作模板表达式。
一种解决方法是展开for循环:

#include <vector>
#include <variant>
#include <array>

using my_type = std::variant<int, float, bool>;
constexpr std::array<int,4> expected_types = {2,2,2,2};
 

bool validate(std::vector<my_type> input) {
  bool rst = false;
  if (input.size() != 4) {
    return false;
  }
  rst = rst || std::get<expected_types[0]>(input[0]);
  rst = rst || std::get<expected_types[1]>(input[1]);
  rst = rst || std::get<expected_types[2]>(input[2]);
  rst = rst || std::get<expected_types[3]>(input[3]);
  return rst;
}

int main()
{
    unsigned long long i = reinterpret_cast<unsigned long long>(nullptr)    ;
}

如果你实际上要做的是检查类型是否与预期的类型匹配,那么你可以使用index方法:

bool validate(std::vector<my_type> input) {
  bool rst = false;
  if (input.size() != 4) {
    return false;
  }
  for (std::size_t i=0; i < 4; i++)
  {
    rst = rst || expected_types[i] == input[i].index();
  }
  return rst;
}
5kgi1eie

5kgi1eie5#

您只能通过指定类型或索引来访问变量,如:

std::get<int>(variant)
std::get<0>(variant)

但是,如果您不显式指定类型或索引,就可以使用访问器来处理从循环中的向量访问变量的问题(我们甚至不需要另一个变量来保存向量中变量类型的索引)
访问者结构可用于对变量的值执行逻辑或操作,并保存稍后返回的结果。

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

using my_type = std::variant<int, float, bool>;
//constexpr int[] expected_types = {2,2,2,2};

struct logicalOrOperationVisitor
{
    bool rst;
    
    logicalOrOperationVisitor(bool b) : rst(b) { }
    
    void operator()(int &i)
    {
        rst = rst || i;
    }
    
    void operator()(float &f)
    {
        rst = rst || f;
    }
    
    void operator()(bool &b)
    {
        rst = rst || b;
    }
};

bool validate(std::vector<my_type> input) {
  logicalOrOperationVisitor orRst(false);
  
  if (input.size() != 4) {
    return false;
  }
  for (int i = 0; i < 4; i++) {
    //rst = rst || std::get<my_type[i]>(input[i]);
    std::visit(orRst, input[i]);
  }
  return orRst.rst;
}
vwoqyblh

vwoqyblh6#

正如我提到的,这种验证是一件痛苦的事情,需要大量的赘言,包括专门化。
这使用了C++17语法,我认为这在2023年是合理的,这也验证了向量中的每个变量实际上都是正确的类型,如果不是,则验证失败,这在问题中没有明确说明,但我相当确定这是隐含的。

#include <utility>
#include <variant>
#include <cstdlib>
#include <vector>
#include <iostream>

using my_type = std::variant<int, float, bool>;
constexpr size_t expected_types[] = {0, 2, 2, 2};

template<typename T>
struct do_validate;

template<size_t ...N>
struct do_validate<std::index_sequence<N...>> {

    static bool validate(const std::vector<my_type> &input)
    {
        if (input.size() != sizeof...(N))
            return false;

        return ( (expected_types[N] ==
              input[N].index() &&
              std::get<expected_types[N]>(input[N])) || ...);
    }
};

bool validate(const std::vector<my_type> &input)
{
    return do_validate<std::make_index_sequence<std::size(expected_types)>>
        ::validate(input);
}

int main()
{
    std::vector<my_type> n{{
            my_type{ std::in_place_index<0>, 1},
            my_type{ std::in_place_index<2>, false},
            my_type{ std::in_place_index<2>, false},
            my_type{ std::in_place_index<2>, false}
        }};

    std::cout << validate(n) << "\n";
    return 0;
}

相关问题