tags:

views:

305

answers:

7

If I want to create a function template, where the template parameter isn't used in the argument list, I can do it thusly:

template<T>
T myFunction()
{
//return some T
}

But the invocation must specify the 'T' to use, as the compiler doesn't know how to work it out.

myFunction<int>();

But, suppose I wanted to do something similar, but for the '[]' operator. template

T SomeObject::operator [ unsigned int ]
{
    //Return some T
}

Is there any way to invoke this operator? This doesn't appear valid:

SomeObject a;
a<int>[3];
+2  A: 

Like with any operator, the function name is operator@, so:

a.operator[]<int>(3);
AProgrammer
+2  A: 

You can use a.operator[]<int>(1); But why do you want this?

maykeye
+7  A: 

This should work:

class C
{
public:
    template <class T>
    T operator[](int n)
    {
        return T();
    }
};

void foo()
{
    C c;

    int x = c.operator[]<int>(0);
}

But it's of no real value because you'd always have to specify the type, and so it looks like a very ugly function call - the point of an operator overload is to look like an operator invocation.

Daniel Earwicker
Nice, I didn't know you could do that! But yeah, doing it that way defeats the niceness of using an operator overload at all.
Scott
Indeed. Usually it gets renamed to `get()`.
GMan
Isn't operator[] supposed to return a reference?
navigator
@navigator - only if the class needs to be considered a container (according to the standard's requirements on containers and iterators). But that part of the original standard is problematic - `std::vector<bool>` doesn't return a reference, and so technically is not a container! And if you aren't specifically extending the container system, you can return whatever you want as far as the language itself is concerned.
Daniel Earwicker
+1  A: 

This may not be an optimal solution, but you could directly call the operator as such:

a.operator[](3);

I tried this in g++ with the following test:

class MyClass {
public:
   template<class T>
   T operator[](unsigned int) {
      // do something
      return T();
   }
};

int main(int argc, char* argv[]) {
   MyClass test;
   test.operator[]<int>(0);
   //test<int>[0]; // doesn't compile, as you mentioned
   return 0;
}
John
It was truly remarkable how fast this got answered. As I was typing this up, I kept seeing answers getting posted, and all of them practically identical. I guess I just wasn't fast enough :)
John
+1  A: 

If you need to define operator[] then probably define the template at the class level. Something like this:

template<class T>
class C
{
public:
    T operator[](int n)
    {
        return T();
    }
};

int  main()
{
    C<int> c;

    int x = c[0];

    return 0;
}
Naveen
I needed it in one class that handles a bunch of different types through the one instance, rather than a bunch of specialised classes that handle their own instances. I think i'll just have to go for the Object.func<int>() form!
Scott
A: 

I have a hard time coming up with an example where this would be needed (couldn't you just overload the operator instead?), but here's my thoughts anyway:

Since you cannot use the infix operator syntax with templatized operators, you might want to do the template instantiation before you call the operator. A proxy might be a way to do this.

class some_class {
private:
  template<class T> class proxy {
    some_class* that_;
  public:
    proxy(some_class* that) : that_(that) {}
    T& operator[](std::size_type idx) {return that->get<T>(idx);}
  };

  template<class T> class const_proxy {
    some_class* that_;
  public:
    proxy(const some_class* that) : that_(that) {}
    const T& operator[](std::size_type idx) const {return that->get<T>(idx);}
  };

  template< typename T >       proxy<T> get_array()       {return proxy<T>(this);}
  template< typename T > const_proxy<T> get_array() const {return proxy<T>(this);}

  template< typename T >       T& get(std::size_t idx)       {/* whatever */}
  template< typename T > const T& get(std::size_t idx) const {/* whatever */}
};

// This is a lousy use case. 
// Did I already say I have a hard time imagining how to use this? 
template< typename T >
void f(some_class& some_object, sid::size_t idx)
{
   T& = some_object.get_array<T>()[idx];
}
sbi
+3  A: 

Boost.Program_options uses this neat syntax:

int& i = a["option"].as<int>();

Which is achieved with something like this:

class variable_value 
{
public:
   variable_value(const boost::any& value) : m_value(value) {}

   template<class T>
   const T& as() const {
       return boost::any_cast<const T&>(m_value);
   }

   template<class T>
   T& as() {
       return boost::any_cast<T&>(m_value);
   }

private:
    boost::any m_value;
};

class variables_map 
{
public:
    const variable_value& operator[](const std::string& name) const
    {
        return m_variables[name];
    }

    variable_value& operator[](const std::string& name)
    {
        return m_variables[name];
    }

private:
    std::map<std::string, variable_value> m_variables;
};

You could adapt this idea to suit your own needs.

dvide