-1

My goal is to have a non member function use a template for a return value. This is so I can return a float array, a double array, etc. I get a "couldn't deduce template parameter 'T'" error.

Here is the method I am trying to use:

template<typename T>
T* make(double magnitude, double frequency, double radians, double seconds,
        int samplesPerSecond) {
    long samples = length(seconds, samplesPerSecond);
    T *wave = new T[samples];
    for (int i = 0; i < samples; i++) {
        wave[i] = magnitude
                * sin(
                        (2.0 * (M_PI) * frequency * i / samplesPerSecond)
                                + radians);
    }
    return wave;
}

I first tried to call the method normally.

double *ds = make(magnitude, frequency, radians, seconds, samplesPerSecond);

I have tried adding the typename after the function name.

double *ds = make<double>(magnitude, frequency, radians, seconds, samplesPerSecond);

I looked over several pages on the web and they have all covered member functions so far and explained that the type cannot be deduced from a return type, so how do you tell the compiler the type?

John Glen
  • 445
  • 2
  • 14
  • Please show the actual declaration of your template. However, it is not possible for a template to deduce a return type. Deduction will only work when the template parameters are used in the function's parameters. – Remy Lebeau Jul 01 '20 at 00:58
  • Added the method. It compiles correctly, so I assumed there was a way for the compiler to deduce the type. Does this mean my best route is to pass in a dummy value? – John Glen Jul 01 '20 at 13:23
  • `I have tried adding the typename after the function name.` and then? what happened? that is how it should be done. what error did you get? – underscore_d Jul 01 '20 at 14:12
  • the type cannot be deduced – John Glen Jul 01 '20 at 20:43

2 Answers2

2

You can very much do this with non-member functions, as per the following example, which adds together two values of a templated type:

#include <iostream>

template<typename T> T add(const T &val1, const T &val2) {
    return val1 + val2;
}

int main() {
    auto eleven = add<int>(4, 7);
    std::cout << "4   + 7   = " << eleven << '\n';
    auto threePointFour = add<double>(1.1, 2.3);
    std::cout << "1.1 + 2.3 =  " << threePointFour << '\n';
}

The output of that code is, as expected:

4   + 7   = 11
1.1 + 2.3 =  3.4

It's possible that your case isn't working because the definition of the templated function may be incorrect - since you haven't supplied that, it's hard to tell for sure. Hence you may want to see how it compares to my own add function as shown above.


As an aside (since your heading indicates this may be what you're attempting), you can also do this without using the templated types in the parameter list (only the return type):

#include <iostream>

template<typename T> T addAndHalve(const double &val1, const double &val2) {
    auto x = (val1 + val2) / 2;
    std::cout << "debug " << x << ": ";
    return x;
}

int main() {
    auto eleven = addAndHalve<int>(4, 7);
    std::cout << "(4   + 7  ) / 2 = " << eleven << '\n';
    auto threePointFour = addAndHalve<double>(1.1, 2.3);
    std::cout << "(1.1 + 2.3) / 2 =  " << threePointFour << '\n';
}

You can see this only affects the return value, using double for all parameters:

debug 5.5: (4   + 7  ) / 2 = 5
debug 1.7: (1.1 + 2.3) / 2 =  1.7
paxdiablo
  • 772,407
  • 210
  • 1,477
  • 1,841
  • This worked. I must have had another error lurking in my code, because it didn't work the first time I tried. I only recently started coding in c++ coming from Java and I'm not sure if it's me, or if c++ really is more picky. Thank you for your help! – John Glen Jul 04 '20 at 13:42
0

I noticed the c++ standard library had functions like lround(), where the l means the function returns a long, so I ended up making multiple methods too.

int16_t* makei(double magnitude, double frequency, double radians,
        double seconds, int samplesPerSecond);
float* makef(double magnitude, double frequency, double radians, double seconds,
        int samplesPerSecond);

This violate the "avoid unnecessary overloading" rule I hear echoed so often, and the following code does indeed work.

double *ds = make<double>(magnitude, frequency, radians, seconds, samplesPerSecond);

I had another unknown error that prevented it from working.

John Glen
  • 445
  • 2
  • 14
  • Those are holdovers from C. This is not necessary. You can template perfectly well, but you just need to tell it what type to return... since you don't provide any argument by which the return type could be deduced. – underscore_d Jul 01 '20 at 14:11
  • You are correct. I was able to get the template to work. Not sure why it didn't work the first time I tried. – John Glen Jul 04 '20 at 13:44