Reputation: 1839
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
.
Upvotes: 3
Views: 257
Reputation: 275385
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.
Upvotes: 3