user13599244
user13599244

Reputation:

Candidate template ignored: couldn't infer template argument 'T'

I know this question probably has been asked before but I'm a beginner to templates, and here is my code,

HeaderFile.h

class Identity  {
    public:    
        template <typename T>
        T getFamilyMembers() {
            if(1) {
              return false;
            }
            std::string whatever = "Test";
            return whatever;
        }
};

Main.cpp

#include "HeaderFile.h"

int main() {
  Identity id;
  std::cout << id.getFamilyMembers() << "\n";
}

Compiler issue two errors,

Main.cpp:25:10: error: no matching member function for call to 'getFamilyMembers'
      id.getFamilyMembers();
      ~~~^~~~~~~~~~
HeaderFile.h:22:11: note: candidate template ignored: couldn't infer template argument 'T'
        T getFamilyMembers() {

Upvotes: 0

Views: 3522

Answers (1)

cdhowie
cdhowie

Reputation: 169211

This isn't how templates work.

The caller specifies what T is. When T is a return type, then all return statements in the function must be a T value, or something implicitly convertible to T. The function itself can't dictate what T is at runtime.

Beyond that, T is known at compile time. You can't return different types in different situations without the help of a variant type like std::variant.

For each distinct T, a totally new version of the function is created. Template functions, therefore, are used when a generic algorithm can be applied to multiple types. For example, a naive implementation of a "swap two values" algorithm might copy one of the values to a temporary variable:

void swap(int & a, int & b) {
    int temp = a;
    a = b;
    b = temp;
}

But now we have to write a new swap() function for each possible type of thing we ever want to swap! Enter templates: we write the function once, as a template:

template <typename T>
void swap(T & a, T & b) {
    T temp = a;
    a = b;
    b = temp;
}

Now the compiler will do the work for us, creating new versions of swap() whenever it sees a T that it hasn't before.


In your particular case, if you want to return a value that might be a string but might be nothing, that's what std::optional is for. In this case, you could return an std::optional<std::string>. You could also just return std::string and use an empty string to notate that there are no family members.

Given that the name of the function implies that multiple items could be returned, it might make more sense to have the function return std::vector<std::string> and then the "no family members" case is simply represented as an empty vector.

Upvotes: 3

Related Questions