Function template for string and int in C++ - c++

I want to have a function template which takes a vector and an element and returns the position of this element in the vector. I want this function to be applicable for both int and std::string types. This is the function template definition:
template<class T>
int findElement(const vector<T> &vec, const T &ele)
{
for(size_t i = 0; i < vec.size(); i++)
{
if(typeid(ele) == typeid(std::string))
{
if(ele.compare(vec[i]) == 0)
return i;
}
else
{
if(ele == vec[i])
return i;
}
}
return -1;
}
As you can see, I am checking the types initially so that I can use the appropriate comparison method. This works fine when I call with std::string type parameters but it gives the following error when I use it with double type:
error C2228: left of '.compare' must have class/struct/union
and
see reference to function template instantiation 'int findElement<double>(const std::vector<_Ty> &,const T &)' being compiled
How do I solve this issue?
Thanks,
Rakesh.

You should never have to check typeid when using templates. std::string defines == in the expected manner, so use it!
template<class T>
int findElement(const vector<T> &vec, const T &ele)
{
for(size_t i = 0; i < vec.size(); i++)
{
if(ele == vec[i])
return i;
}
return -1;
}
In general, if you need to special-case your templated function for a particular type, use a template specialization:
template<class T>
int findElement(const vector<T> &vec, const T &ele) {
for(size_t i = 0; i < vec.size(); i++) {
if(ele == vec[i])
return i;
return -1;
}
template<>
int findElement<std::string>(const vector<std::string> &vec, const std::string &ele) {
for(size_t i = 0; i < vec.size(); i++) {
if(ele.compare(vec[i]) == 0)
return i;
}
return -1;
}

std::string has operator ==, however, if you want call different methods from T - you should specialize, or overload function. Typeid can't help, since it's runtime type identification.
Example of overloading
template<class T>
int findElement(const vector<T> &vec, const T &ele)
{
for(size_t i = 0; i < vec.size(); i++)
{
if(ele == vec[i])
return i;
}
return -1;
}
int findElement(const vector<string>& vec, const string& ele)
{
for (size_t i = 0; i < vec.size(); ++i)
{
if (ele.compare(vec[i]) == 0)
return i;
}
return -1;
}
also, you can use function overloading only for compare, since loop is the same.

Related

template-determined class as return-type of a template function, that uses template template parameters

I have std::vector<double> , and my type Array-like.
Also, there are a lot of numbers in std::vector<double> source, and I would like to make this code work in the way:
std::cout << toHisto(source, /* other parameters like min, max, stacks */);
And I guessed that would be good, if the function toHisto worked with other containers, such as with my Array. Thou, I tried to do this, and have a problem in return type of template function Error C3200 'Container<double,std::allocator<double>>': invalid template argument for template parameter 'Container', expected a class template
If you have any proposals, I would be glad to hear.
Code here:
template<template <class T, class Allocator = std::allocator<T>> class Container>
class MyClassForOstream {
public:
Container<double> &res;
double min;
double max;
MyClassForOstream(Container<double> r, double min_, double max_) : res(r), min(min_), max(max_) {}
friend std::ostream& operator<< (std::ostream& out, MyClassForOstream const& s) {
/* sth like for(i in s)"out << s[i]" , and some format stuff from <iomanip>*/
return out;
}
};
template<template <class T, class Allocator = std::allocator<T>> class Container>
// Error here at specifing params for MyClassForOstream < /* here */>
MyClassForOstream<Container<double>> toHisto(Container<double> const& gen, double min, double max, size_t stocks) { // class template must have: operator[], .size(), ctor(size)
Container<size_t> tmp(stocks);
for (size_t i = 0; i != stocks; ++i) {
tmp[i] = 0;
}
for (size_t i = 0; i != gen.size(); ++i) {
++tmp[static_cast<size_t>(((min + gen[i]/(max+min))*((max-min)*stocks)))];
}
Container<double> res(stocks);
for (size_t i = 0; i != res.size(); ++i) {
res[i] = 0;
}
for (size_t i = 0; i != res.size(); ++i) {
res[i] = static_cast<double>(tmp[i])/gen.size();
}
return MyClassForOstream<Container<double>> (res, min, max ); // also error here
}```

sorting array of pointers in c++ using lambdas

I am trying to write sorting template function to make it work with custom classes.
My code is:
#include <iostream>
#include <vector>
struct test
{
int value;
test(int a) : value(a){};
void print() { printf("the value is : %d", value); };
};
template <class T>
void bubblesort(T *m_data, size_t size, bool (*cmp)(const T &l, const T &r))
{
for (uint32_t i = 0; i < size; i++)
for (uint32_t j = 1; j < size - i; j++)
if (cmp(m_data[j - 1], m_data[j]))
{
T temp = m_data[j];
m_data[j] = m_data[j - 1];
m_data[j - 1] = temp;
}
}
int main()
{
std::vector<test> arr;
for (size_t i = 0; i < 10; i++)
arr.emplace_back(i);
std::vector<test *> arr1;
for (auto &i : arr)
arr1.emplace_back(&i);
bubblesort<test>(&arr[0], arr.size(), [](const test &l, const test &r) { return l.value < r.value; });
// bubblesort<test*>(&arr1[0], arr1.size(), [](const test *&l, const test *&r) { return l->value < r->value; });
for (auto i : arr)
printf("%d\n", i.value);
}
My question is how do you sort arr1 using the bubblesort function above? What kind of modification do I have to make in my code to be able to do so?
uncommenting the bubblesort line gives error
error: invalid user-defined conversion from 'main()::<lambda(const test*&, const test*&)>' to 'bool (*)(test* const&, test* const&)' [-fpermissive]
[build] 48 | bubblesort<test *>(&arr1[0], arr1.size(), [](const test *&l, const test *&r) { return l->value < r->value; });
Your function has the wrong type; T is test*, so you need test* const& - "reference to const pointer to test" - as the error message says.
(const test*& is "reference to pointer to const test.)
Your solution cannot work with templates...it cannot deduce the parameters type.
Consider modifying your code as follow:
struct test
{
int value;
explicit test(int a) : value(a) {};
void print() { printf("the value is : %d", value); };
};
template <class T, class _cmp>
void bubblesort(T *m_data, size_t size, _cmp cmp)
{
for (uint32_t i = 0; i < size; i++)
for (uint32_t j = 1; j < size - i; j++)
if (cmp(m_data[j - 1], m_data[j]))
{
T temp = m_data[j];
m_data[j] = m_data[j - 1];
m_data[j - 1] = temp;
}
}
int main()
{
std::vector<test> arr;
for (int i = 0; i < 10; i++)
arr.emplace_back(i);
std::vector<test *> arr1;
for (auto i : arr)
arr1.emplace_back(&i);
bubblesort<test>(&arr[0], arr.size(), [](const test &l, const test &r) -> bool { return l.value < r.value; });
bubblesort<test*>(&arr1[0], arr1.size(), [](const test* l, const test* r) -> bool { return l->value < r->value; });
for (auto i : arr)
printf("%d\n", i.value);
}

Is there any workaround for MSVC producing `Internal compiler error` for this code?

For some reason the below code gives me fatal error C1001: Internal compiler error. with MSVC 19.27, but not with Clang. Any idea how to write it so that the static_assert can be done also on MSVC?
template <typename T, int N, typename K, int M>
constexpr int countIdentifersNotInArray(const T(&identifiers)[N], const K(&array)[M]) {
auto find = [&array](const unsigned char value) {
for (const auto& a : array) {
if (a == value) {
return true;
}
}
return false;
};
int count = 0;
for (const auto& value : identifiers) {
if (!find(value)) {
++count;
}
}
return count;
}
constexpr bool testIt() {
return countIdentifersNotInArray({ 0x01, 0x02 }, { 0x01 });
}
int main() {
static_assert(testIt());
return 0;
}
I would like to use this in a an environment where stl is not available, so solutions without that are most interesting.
As the comment has pointed out, this is an MSVC bug and you should definitely report to Microsoft.
By removing multiple lines until it stops crashing the compiler, I believe the cause is the range-for loops. So, since they're arrays with known size, you can workaround with the classic indexed loops:
template <typename T, int N, typename K, int M>
constexpr int countIdentifersNotInArray(const T(&identifiers)[N], const K(&array)[M]) {
auto find = [&array](const auto value) {
for (int i = 0; i < M; i++) {
if (array[i] == value) {
return true;
}
}
return false;
};
int count = 0;
for (int i = 0; i < N; i++) {
if (!find(identifiers[i])) {
++count;
}
}
return count;
}
It works on MSVC.

Custom structure as key in unordered_map

I want to use structure Item as key in unordered_map
I implemented structures for hash and equal operations.
But I have an error
hashtable_policy.h:1384:16: error: no match for call to '(const ItemHash) (const Item&)'
solution.cpp:28:12: note: candidate: 'size_t ItemHash::operator()(Item)'
32 | size_t operator()(Item item) {
solution.cpp:28:12: note: passing 'const ItemHash*' as 'this' argument discards qualifiers
How can I fix the error?
My code
vector<int> get_key(const string& s) {
vector<int> res(26, 0);
for (int i = 0; i < s.size(); ++i) {
int pos = s[i] - 'a';
res[pos]++;
}
return res;
}
struct Item {
vector<int> v;
Item(const vector<int>& vec) : v(vec) {}
bool operator==(Item other) {
if (v.size() != other.v.size()) {
return false;
}
for (int i = 0; i < v.size(); ++i) {
if (v[i] != other.v[i]) {
return false;
}
}
return true;
}
};
struct ItemHash {
size_t operator()(Item item) {
auto vec = item.v;
size_t seed = vec.size();
for(auto& i : vec) {
seed ^= i + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
};
struct ItemEqual {
bool operator()(Item item1, Item item2) {
return item1 == item2;
}
};
vector<vector<int> > Solution::anagrams(const vector<string> &A) {
vector<vector<int>> res;
unordered_map<Item, vector<int>, ItemHash, ItemEqual> hash; // hash_key, vector of indexes
for (int i = 0; i < A.size(); ++i) {
Item item = Item(get_key(A[i]));
hash[item].push_back(i);
}
for (const auto& i : hash) {
res.push_back(i.second);
}
return res;
}
You need to const-qualify ItemHash::operator()(Item), i.e.,
struct ItemHash {
size_t operator()(Item item) const
// ^^^^ here
{
// as before...
}
Note that as #JeJo pointed out in the comments, you need the same fix for ItemEqual.

Avoid function overloading with help of template

I have the following overloaded functions:
float myFunc(Vector2D vec) {
Temp2D temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
float myFunc(Vector3D vec) {
Temp3D temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
float myFunc(Vector4D vec) {
Temp4D temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
where computeTemp is also overloaded for Vector2D, Vector3D, Vector4D:
Temp2D computeTemp(Vector2D, int);
Temp3D computeTemp(Vector3D, int);
Temp4D computeTemp(Vector4D, int);
To avoid code duplication, I have come up with the idea to add a layer of abstraction:
template<typename T0, typename T1>
float myFunc(T0 vec) {
T1 temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
float myFunc(Vector2D vec) {
return myFunc<Vector2D, Temp2D>(vec);
}
float myFunc(Vector3D vec) {
return myFunc<Vector3D, Temp3D>(vec);
}
float myFunc(Vector4D vec) {
return myFunc<Vector4D, Temp4D>(vec);
}
However, I want to know if it is possible to avoid an additional layer of abstraction and directly decide the type of variable temp in myFunc.
directly decide the type of variable temp in myFunc.
You can use decltype to determine the type, e.g.
template<typename T0>
float myFunc(T0 vec) {
decltype(computeTemp(vec, 0)) temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
BTW,
1. Note that if computeTemp returns by reference instead of return-by-value, the result type of decltype would also be reference (to lvalue or rvalue, depending on how computeTemp returns); you might need to use std::remove_reference with decltype to get the type you want.
2. The expression used for decltype belongs to unevaluated expressions:
The operands of the four operators typeid, sizeof, noexcept, and decltype (since C++11) are expressions that are not evaluated (unless they are polymorphic glvalues and are the operands of typeid), since these operators only query the compile-time properties of their operands. Thus, std::size_t n = sizeof(std::cout << 42); does not perform console output.
Or using auto instead of decltype()
template <typename VT>
float myFunc(VT vec) {
auto temp = computeTemp(vec, 0);
for (int i = 1; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}
This starting from C++11 (same limit for decltype()).
For C++98, the best I can imagine is the creation of a custom type traits to select the temp type.
Something like [caution: code not tested]
template <typename>
struct tempType;
template <> struct tempType<Vector2D> { typedef Temp2D type; };
template <> struct tempType<Vector3D> { typedef Temp3D type; };
template <> struct tempType<Vector4D> { typedef Temp4D type; };
template <typename VT>
float myFunc(VT vec) {
typename tempType<VT>::type temp;
for (int i = 0; i < 10; i++) {
temp += computeTemp(vec, i);
}
return temp.compute_a_float();
}