2

I need to build a vector of a class that can have multiple type like this:

#include <variant>
#include <vector>
#include "Field.h"

using namespace std;

int main()
{
    variant <int, float> v;
    vector <variant<Field<int>, Field<string>, Field<float>>> fdList;
    fdList[0].getName();
}

And this is header file Field.h:

#pragma once
#include <string>
#include <vector>

using namespace std;

template<class T>
class Field
{
public:
    Field();
    Field(string);
    void setName(string);
    string getName();
    bool isPrime();
    void toPrime();
    void toForeign(Field);
    ~Field();

private:
    string FD_Name;
    vector <T> records;
    bool isPrimeK = false;
    string message;
};

template<class T>
string Field<T>::getName()
{
    return FD_Name;
}

When I try to access getName() function, Visual Studio keeps giving me the following message error:

E0135 class "std::variant<Field, Fieldstd::string, Field>" has no member "getName"
C2039 'getName': is not a member of 'std::variant<Field,Fieldstd::string,Field>'

But it works just fine, if I define my vector like this:

vector <Field<int>> fdList;
fdList[0].getName();

How can I fix this?

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96

2 Answers2

1

For any issue about standard library, I recommend you to check document first. You can see here about how to use std::variant.

In short, you cannot access the content in your std::variant like that because its type is std::variant but not the types you store in it. For your case, I think you may want to check what's inside first by calling std::variant::index() method, then get the value by calling std::get.

LIU Qingyuan
  • 524
  • 5
  • 18
  • i get another issue while trying your solution. I can do `get<0>(fdList[0]).getName();` but i can't do `int i = 0; get(fdList[i]).getName();` – Hoàng Thái Vương Aug 28 '20 at 04:11
  • @HoàngTháiVương template parameter(what enclosed by <>) should be compile time constant, so it cannot be a variable. Use a switch or if-else chain to check what is inside, and use corresponding int literal (0,1,2) to extract stuff inside – LIU Qingyuan Aug 28 '20 at 08:25
  • BTW you may also use ```std::get>``` instead of ```std::get<0>```, which is more intuitive and self-explaining – LIU Qingyuan Aug 28 '20 at 08:27
1

Calling a method on variant doesn't automatically call the method of the active alternative of variant. You'll have to visit the active alternative and invoke the corresponding handler. In your case, since you want to handle all of the potential active alternatives the same way, you can do:

std::visit([](const auto& field) {
  field.getName();
  // ...
}, fdList[0]);

Alternatively, you can wrap the variant in something like:

struct AnyField {
  string getName() const {
    return std::visit([](const auto& field) { return field.getName(); }, v);
  }

  std::variant<Field<int>, Field<string>, Field<float>> v;
};

then use them like you wanted to:

vector<AnyField> fdList;
fdList[0].getName();
mpark
  • 7,574
  • 2
  • 16
  • 18