I'm encountering issues when I try to use this operator ()
function in a class on a string object instead of a char or numeric data type. I tried the following implementation to check if the data being iterated over is a std::string
, but the function is still returning an error when this part of the code is executed:
this->current -= this->range->step;
This makes sense, sense you can't perform that operation on a std::string
, however my current method of making an exception for strings isn't quite working right, it keeps throwing:
error: no match for 'operator-=' (operand types are 'std::__cxx11::basic_string<char>' and 'std::__cxx11::basic_string<char>' this->current -= this->range->step;
Any ideas on a better implementation, or perhaps a different way to write this code?
Iterator& operator () {
bool isStr = false;
std::string str = "s";
auto cmp = this->range->step;
if (typeid(cmp) == typeid(str)) { // check if the variable is a string
isStr = true;
}
if (this->range->stop > this->range->start || isStr) { // if increasing, or working w/ strings
this->current = range->step;
return *this;
} else if (this->range->stop < this->range->start) { // if decreasing
if (!isStr) {
this->current -= this->range->step;
}
}
return *this;
}
CodePudding user response:
You are checking the type at runtime, which won't work. You need to check the type at compile time instead.
In C 17 and later, you can use if constexpr
for that, eg:
#include <type_traits>
Iterator& operator () {
if constexpr (std::is_same_v<decltype(range->step), std::string>) { // check if the variable is a string
current = range->step;
}
else if (range->stop > range->start) { // if increasing
current = range->step;
}
else if (range->stop < range->start) { // if decreasing
current -= range->step;
}
return *this;
}
In earlier C versions, you will have to instead overload the operator using SFINAE (std::enable_if()
, etc) or template specialization to isolate the std::string
version of the operator into its own separate implementation.
CodePudding user response:
Like your code this isn't complete and won't compile. But when working with code that should make choices dependent on type use compile time constructs! Use things, like "overloading", "templates", "if constexpr", "SFINAE". For example :
#include <type_traits>
#include <string>
struct foo_t
{
template<typename type_t>
auto& operator ()
{
if constexpr (std::is_same_v<type_t, std::string>) // <== check types at compile time!
{
// working with strings we go only one way
current = range->step;
return *this;
}
else
{
// if increasing
if (range->stop > range->start )
{
current = range->step;
return *this;
}
else if (range->stop < range->start)
{
current -= range->step;
}
}
return *this;
}
};