3

I am trying to learn c++ templates. One function in a script compiles, whilst a seemingly similar function fails. The entire script is:

#include <string>
#include <vector>
using std::vector;

template <typename T>
void works(vector<int>& vi, vector<double>& vd, vector<T>& inp) {
    if (std::is_same<T, double>::value)
        vd.push_back(inp[0]);
    else if (std::is_same<T, int>::value)
        vi.push_back(inp[0]);
}

template <typename T>
void doesnt_work(vector<std::string>& vs, vector<double>& vd, vector<T>& inp) {
    if (std::is_same<T, double>::value)
        vd.push_back(inp[0]);
    else if (std::is_same<T, std::string>::value)
        vs.push_back(inp[0]);  // Line 18:  no matching member function
}

int main() {
    vector<double> d = {2, 3, 4};
    vector<double> doubles;
    vector<std::string> strings;
    vector<int> ints;
    doesnt_work(strings, doubles, d);  // Line 26: Comment out and script runs
    works(ints, doubles, d);
    return 0;
}

The function works takes the two vectors vi and vd containing int and double as references, as well as a third vector with elements of type T. I then try to check for the type of T and push the first element of the vector inp into either vi or vd. In contrast, the function doesnt_work causes problems. Instead of accepting a vector of int as parameter, it accepts a vector of std::string. I can run the entire script when I comment out line 26. Otherwise, clang++ tells me that

error: no matching member function for call to 'push_back'
        vs.push_back(inp[0]);

Does somebody kindly have any idea what I am doing wrong? I do not understand why the program cannot access the function push_back of the vector vs.

2
  • offtopic: if it is only either doubles or strings using simple overloads is sufficient Commented May 15, 2019 at 14:08
  • @Harry Thanks for your answer! Your suggestion does indeed work. However, if I generalize the script the program fails again. For example, if I change the input inp to be a vector of string instead of a vector of double the other branch of the if statement in doesnt_work causes problems. Commented May 15, 2019 at 14:24

1 Answer 1

3
template <typename T>
void now_works(vector<std::string>& vs, vector<double>& vd, vector<T>& inp) {
  if constexpr (std::is_same<T, double>::value)
    vd.push_back(inp[0]);
  else if constexpr (std::is_same<T, std::string>::value)
    vs.push_back(inp[0]);  // Line 18:  no error
}

your problem is that all branches are compiled even if they aren't run.

if constexpr makes them compiled, then discards them at compile time, ignoring any type errors.

The code that worked, everything could convert even if not run, so it compiled.

The code that didn't work, the conversion you wanted to exclude is illegal, so it failed at compile time.

Note that if constexpr only works because the branching clause is a compile-time constant, and because it is in a template, and the clause is dependent on the template parameters, and the code that is invalid is also dependent on the template parameters.

If you don't have if constexpr yet because you are stuck on an old version of C++, you will be forced to do something ugly like tag dispatching or SFINAE with helper functions or something more arcane.

Sign up to request clarification or add additional context in comments.

1 Comment

@Yaak, thanks for your kind and detailed answer. There's a lot to learn for me from that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.