I'm finally trying to learn templates and I created a template function that will return an std::vector
with a generic type.
When compiling I get an error:
error: no matching function for call to ‘std::vector::push_back(std::string&)’
Is there a way to support std::string
or a comparable type in the template vector in addition to the primitive types?
Here is a 'Minimal, Reproducible Example' that doesn't compile due to this error (this is obviously not my code, it just illustrates the error):
#include <iostream>
#include <vector>
enum types{
TINT = 0,
TDOUBLE = 1,
TSTRING = 2,
};
class TestClass{
public:
template<typename T> std::vector<T> getData(types type)
{
std::vector<T> entries;
int i_value;
double d_value;
std::string st_value;
switch (type)
{
case types::TINT:
i_value = 1;
entries.push_back(i_value);
break;
case types::TDOUBLE:
d_value = 0.1;
entries.push_back(d_value);
break;
case types::TSTRING:
st_value = "foo";
entries.push_back(st_value); //Pushing an std::string causes a compile error
break;
default:
break;
}
return entries;
}
};
int main()
{
TestClass bar;
std::vector<int> test = bar.getData<int>(types::TINT);
return 0;
}
Commenting the line entries.push_back(st_value);
makes everything compile again.
CodePudding user response:
The code does not compile because you try to check the types at runtime. This is too late. Use std::is_same
to make a compile time check.
template<typename T> std::vector<T> getData()
{
std::vector<T> entries;
int i_value;
double d_value;
std::string st_value;
if constexpr(std::is_same_v<T, int>) {
i_value = 1;
entries.push_back(i_value);
}
else if constexpr(std::is_same_v<T, double>) {
d_value = 0.1;
entries.push_back(d_value);
}
else if constexpr(std::is_same_v<T, std::string>) {
st_value = "foo";
entries.push_back(st_value);
}
return entries;
}
CodePudding user response:
This line std::vector<int> test = bar.getData<int>(types::TINT);
caused the compiler to expand the function to be:
// Note: T becomes int
std::vector<int> getData(types type)
{
// Note: T becomes int
std::vector<int> entries;
int i_value;
double d_value;
std::string st_value;
switch (type)
{
case types::TINT:
i_value = 1;
entries.push_back(i_value);
break;
case types::TDOUBLE:
d_value = 0.1;
entries.push_back(d_value);
break;
case types::TSTRING:
st_value = "foo";
entries.push_back(st_value); //Pushing an std::string causes a compile error
break;
default:
break;
}
return entries;
}
Which means, entries
is a vector of integers. It cannot take a std::string
object.