1

I want to write a generic function that passes a generic parameter to a function that has several overloads. The C++ equivalent would be this. Here is what I tried:

public void setUniform1<T>(int loc, T value) {
    GL.Uniform1(loc, value);
}

However this gives me the error

error CS1503: Argument 2: cannot convert from 'T' to 'double'

GL.Uniform1 takes several types for the value paramter and I guess double is the first overload, that's why it's trying to convert to double.

So how do I do this?

gartenriese
  • 4,131
  • 6
  • 36
  • 60

2 Answers2

2

C++ templates and .NET generics only look the same, but behave differently: .NET generics need to be resolvable completely at compile time. In your example, that is not possible.

You can achieve a similar result to C++ templates with the dynamic keyword:

public void setUniform1<T>(int loc, T value) {
    GL.Uniform1(loc, (dynamic)value);
}

This will defer the overload resolution to the runtime at which point the type of value is actually known.
But, this has the issue that it will throw an exception if there is no overload of GL.Uniform1 for the type of value.
Still, I have used this exact approach a couple of times. It makes sense when you can be certain that you will receive only a certain set of types and have overloads for all of them.
Another solution to avoid the runtime exception would be to provide an overload that takes object and performs a default action.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
1

Perhaps you should pass a double instead, since that's what your function needs.

  public void setUniform1(int loc, double value) 
  {
      GL.Uniform1(loc, value);
  }

Generic types are only useful when you don't need a specific datatype, but in this case you do.


C# does not have a numeric generic type constraint.

Given that there are several versions of GL.Uniform, each of which takes a specific datatype, normally you would need three versions of the function.

However, since both float and int can be converted to a double without loss of precision, you could probably get away with just one function (taking a double).

  int    i;
  float  f;
  double d;

  setUniform1(loc, i);   // implicit conversion int   => double
  setUniform1(loc, f);   // implicit conversion float => double
  setUniform1(loc, d);

See Implicit Numeric Conversions.

Community
  • 1
  • 1
  • No, GL.Uniform1 can also take a float or an int, not only a double. If it would only take a double I would not need a generic method. – gartenriese Mar 23 '16 at 11:31
  • @gartenriese I am not sure that you actually need a generic method. You might be biased by your C++ background and their templates. How are you actually calling `setUniform1`? Where are the values coming from that you pass? – Daniel Hilgarth Mar 23 '16 at 11:33
  • @DanielHilgarth: I want to call `setUniform1` with either int, float, or double. There will also be a `setUniform2` which will take other types and call GL.Uniform2. I thought it could save me from copying and pasting all methods for each type. – gartenriese Mar 23 '16 at 11:37