2

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!

Francesco Feltrinelli
  • 1,589
  • 1
  • 10
  • 14

2 Answers2

1

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) {}
Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • Thank you! Overloaded functions could be a solution. As regards templates, how could I fit TypeA and TypeB which are unrelated with no common base class? – Francesco Feltrinelli Feb 23 '11 at 14:40
  • Templates do not care about the actual parameter types. The only thing that matters is that whatever operations you perform on the type-parameterized objects are valid for objects of the actual type. If the code for the two types is the same, use a template. Otherwise, overloaded functions might be the way to go. – Ferruccio Feb 23 '11 at 14:59
1

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.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • Thank you! But what do you mean with `__temporary__` ? If you mean a compiler temporary object, wouldn't it be created only with a call to eg. "foo(TypeA());" ? In your first solution, does the conversion from TypeA to Type require a copy, eg. as in "TypeA a; Type t=a; foo(&t);" ? Nice your second solution, I'll think about it! As regards templates, how could I fit TypeA and TypeB which are unrelated with no common base class? – Francesco Feltrinelli Feb 23 '11 at 14:38
  • @Francesco: The compiler copies `a` into a temporary object of type `Type` (the variant) and then performs the call to `foo` with this temporary object. // Templates are meant for unrelated types, as long as the methods required are present in both. – Matthieu M. Feb 23 '11 at 15:30