Pass an object of a type aggregated by a boost::variant to a function that accepts that boost::variant

1.4k views Asked by At

Suppose I have:

class TypeA { };
class TypeB { };
typedef boost::variant<TypeA, TypeB> Type;
  1. This is ok:

    void foo(Type t) { };
    
    int main(){
        TypeA a;
        foo(a);
    }
    
  2. This does not compile:

    void foo(Type &t) { };
    
    int main(){
        TypeA a;
        foo(a);
    }
    

    with the error:

    invalid initialization of reference of type ‘Type&’ from expression of type ‘TypeA’

  3. Also this does not compile:

    void foo(Type *t) { };
    
    int main(){
        TypeA a;
        foo(&a);
    }
    

    with the error:

    cannot convert ‘TypeA*’ to ‘Type*’ for argument ‘1’ to ‘void foo(Type*)’

Is there a way to pass to a function that accepts a boost::variant an instance of one of the types aggregated by that boost::variant, either through a reference (as in case 2) or a pointer (as in case 3)?

Thank you very much!

2

There are 2 answers

2
Matthieu M. On BEST ANSWER

What really happens in 1:

TypeA a;
Type __temporary__(a);
foo(__temporary__);

What cannot happen in 2 or 3:

TypeA a;
Type* __temporary__(&a);
  // this fails because there is no inheritance relationship
foo(__temporary__);

You have two solutions (for a non template foo):

  • convert to Type, then take a pointer/reference to this
  • create a boost::variant<TypeA*,TypeB*> for implicit conversion to kick in

A third solution is to change foo itself, and make it template. It depends on what you want to do.

2
Ferruccio On

Aggregation implies that the boost::variant contains both TypeA and TypeB. It doesn't. It contains either TypeA or TypeB. It's more like a union than a struct.

You can pass TypeA by value because there is an implicit conversion from TypeA to Type.

There is no implicit conversion from TypeA& to Type& (or TypeA* to Type*) and there shouldn't be. Think of what would happen if a reference to a TypeA object was passed into foo() and foo() decides to replace it with a TypeB value.

Without knowing what foo() and TypeA/TypeB are, I can't give you more specific advice but perhaps you can use a function template. i.e.

template <typename T>
void foo(T& t) {}

or overloaded functions:

void foo(TypeA& t) {}
void foo(TypeB& t) {}