sharvey
sharvey

Reputation: 8185

Unspecified template argument

I'm trying to use templates with multiple to pass data onto a function, but using only the first template argument as a filter. Something like this:

template <typename A, typename B>
class Component {

};

template <typename A>
class Context {
    public:
        void add(Component<A, void *> comp) {
        }
}

typedef struct Foo { int x; } Foo;
typedef struct Bar { int y; } Bar;
Context<Foo> *context = new Context<Foo>();
Component<Foo, Bar> *comp = new Component<Foo, Bar>();
context->add(comp); // error

But the compiler complains that it cannot convert Component<Foo, Bar> to Component<Foo, void *>. Is there a way to accomplish this?

Upvotes: 2

Views: 869

Answers (3)

Xeo
Xeo

Reputation: 131907

Yes, add a converting copy constructor to your Component:

template<class U, class V>
Component(Component<U,V> const& other){
  // ...
};

But that is still refineable with the appropriate enable_if SFINAE guard:

// <tr1/type_traits> for C++03
#include <type_traits> // for C++0x

template<class T, class U>
struct can_convert{
  // std::tr1::... for C++03
  static bool const value =
      std::is_same<T,U>::value || std::is_convertible<T,U>::value;
};

template<class C1, class C2>
struct ice_and{
  static bool const value = C1::value && C2::value;
}

// define for clarity and brevity
#define IF_CAN_CONVERT(A,B,U,V) \
  typename std::enable_if<ice_and<can_convert<A,U>,can_convert<B,V> > >::type* = 0

template<class U, class V>
Component(Component<U,V> const& other, IF_CAN_CONVERT(A,B,U,V)){
  // ...
};

Upvotes: 0

Tony Delroy
Tony Delroy

Reputation: 106244

I'm trying to use templates with multiple to pass data onto a function, but using only the first template argument as a filter. [...] But the compiler complains that it cannot convert Component to Component. Is there a way to accomplish this?

Well, your filter works doesn't it: your add function will only match a Component whose second template parameter is void*, and you're providing Bar. What else could you possibly expect? If you want it to handle other "second-parameters" as well, either remove the filter, provide an fallback function for it to match, or some kind of conversion.

Upvotes: 0

StackedCrooked
StackedCrooked

Reputation: 35545

I think what you probably need to do is change the signature of the 'add' method:

template <typename A>
class Context
{
public:
  template<class B>
  void add(Component<A, B> comp)
  {           
  }
};

However, I don't know the details of your problem so this is a mere guess.

Upvotes: 1

Related Questions