I want to fill a vector with different functions depending on the data type of vector. Now I have three types to consider: int, double, string. If I only consider int and double, the code works perfectly. But if I include string into the template, the code fails. I don't understand why the if statement for string doesn't work. Here is the code:
#include <iostream>
#include <vector>
#include <map>
#include <string>
template <typename T>
void fillV(std::vector<T> &res) {
if (std::is_same<T, double>::value ) res.push_back(3.5);
else if (std::is_same<T, int>::value) res.push_back(2);
else if (std::is_same<T, std::string>::value) res.push_back(std::string("hello"));
}
int main()
{
std::vector<std::string> t;
std::vector<double> t1;
std::vector<int> t2;
fillV<std::string>(t);
fillV<double>(t1);
fillV<int>(t2);
std::cout << t[0] << "\n";
std::cout << t1[0] << "\n";
std::cout << t2[0] << "\n";
}
The error information is
input
stderr
Compilation failed due to following error(s).main.cpp: In instantiation of ‘void fillV(std::vector<T>&) [with T = std::basic_string<char>]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',27)">main.cpp:27:25</span>: required from here
main.cpp:16:42: error: no matching function for call to ‘std::vector >::push_back(double)’
if (std::is_same<T, double>::value ) res.push_back(3.5);
^~~
In file included from /usr/include/c++/6/vector:64:0,
from main.cpp:10:
/usr/include/c++/6/bits/stl_vector.h:914:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::basic_string; _Alloc = std::allocator >; std::vector<_Tp, _Alloc>::value_type = std::basic_string]
push_back(const value_type& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:914:7: note: no known conversion for argument 1 from ‘double’ to ‘const value_type& {aka const std::basic_string&}’
/usr/include/c++/6/bits/stl_vector.h:932:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = std::basic_string; _Alloc = std::allocator >; std::vector<_Tp, _Alloc>::value_type = std::basic_string]
push_back(value_type&& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:932:7: note: no known conversion for argument 1 from ‘double’ to ‘std::vector >::value_type&& {aka std::basic_string&&}’
main.cpp:17:43: error: no matching function for call to ‘std::vector >::push_back(int)’
else if (std::is_same<T, int>::value) res.push_back(2);
^~~
In file included from /usr/include/c++/6/vector:64:0,
from main.cpp:10:
/usr/include/c++/6/bits/stl_vector.h:914:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::basic_string; _Alloc = std::allocator >; std::vector<_Tp, _Alloc>::value_type = std::basic_string]
push_back(const value_type& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:914:7: note: no known conversion for argument 1 from ‘int’ to ‘const value_type& {aka const std::basic_string&}’
/usr/include/c++/6/bits/stl_vector.h:932:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = std::basic_string; _Alloc = std::allocator >; std::vector<_Tp, _Alloc>::value_type = std::basic_string]
push_back(value_type&& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:932:7: note: no known conversion for argument 1 from ‘int’ to ‘std::vector >::value_type&& {aka std::basic_string&&}’
main.cpp: In instantiation of ‘void fillV(std::vector<T>&) [with T = double]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',28)">main.cpp:28:21</span>: required from here
main.cpp:18:51: error: no matching function for call to ‘std::vector::push_back(std::string)’
else if (std::is_same<T, std::string>::value) res.push_back(std::string("hello"));
^~~
In file included from /usr/include/c++/6/vector:64:0,
from main.cpp:10:
/usr/include/c++/6/bits/stl_vector.h:914:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = double; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = double]
push_back(const value_type& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:914:7: note: no known conversion for argument 1 from ‘std::string {aka std::basic_string}’ to ‘const value_type& {aka const double&}’
/usr/include/c++/6/bits/stl_vector.h:932:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = double; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = double]
push_back(value_type&& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:932:7: note: no known conversion for argument 1 from ‘std::string {aka std::basic_string}’ to ‘std::vector::value_type&& {aka double&&}’
main.cpp: In instantiation of ‘void fillV(std::vector<T>&) [with T = int]’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',29)">main.cpp:29:18</span>: required from here
main.cpp:18:51: error: no matching function for call to ‘std::vector::push_back(std::string)’
else if (std::is_same<T, std::string>::value) res.push_back(std::string("hello"));
^~~
In file included from /usr/include/c++/6/vector:64:0,
from main.cpp:10:
/usr/include/c++/6/bits/stl_vector.h:914:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = int; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = int]
push_back(const value_type& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:914:7: note: no known conversion for argument 1 from ‘std::string {aka std::basic_string}’ to ‘const value_type& {aka const int&}’
/usr/include/c++/6/bits/stl_vector.h:932:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = int; _Alloc = std::allocator; std::vector<_Tp, _Alloc>::value_type = int]
push_back(value_type&& __x)
^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:932:7: note: no known conversion for argument 1 from ‘std::string {aka std::basic_string}’ to ‘std::vector::value_type&& {aka int&&}’
Updated on 04/14/2021: Since I can't answer my own question, I will add one more solution other than the overloading, which is by Partial template specialization. It works before C++17. The code is inspired by the first answer, thank you.
template <typename T, int i>
struct test;
template <typename T>
struct test<T, 1> {
void fillV(std::vector<T> &res) {
res.push_back(3.5);
}
};
template <typename T>
struct test<T, 2> {
void fillV(std::vector<T> &res) {
res.push_back(2);
}
};
template <typename T>
struct test<T, 3> {
void fillV(std::vector<T> &res) {
res.push_back("Hello");
}
};
int main()
{
std::vector<std::string> t;
std::vector<double> t1;
std::vector<int32_t> t2;
test<double, 1> a1;
a1.fillV(t1);
test<int32_t, 2> a2;
a2.fillV(t2);
test<std::string, 3> a;
a.fillV(t);
std::cout << t[0] << "\n";
std::cout << t1[0] << "\n";
std::cout << t2[0] << "\n";
}
Updated on 04/17/2021: Moreover, if overloading is used, the following code would be enough.
void fill_v(std::vector<double>& res) { res.push_back(3.5); }
void fill_v(std::vector<int>& res) { res.push_back(2); }
void fill_v(std::vector<std::string>& res) { res.push_back(std::string("hello")); }
int main()
{
std::vector<std::string> t;
std::vector<double> t1;
std::vector<int32_t> t2;
fillV(t1);
fillV(t2);
fillV(t);
std::cout << t[0] << "\n";
std::cout << t1[0] << "\n";
std::cout << t2[0] << "\n";
}